堆内存模型
JVM 将对象存放在堆内存中,堆内存所需要的空间是比较大的。我们对于 JVM 的调优
也主要是针对堆内存的调优,比如分配堆内存的空间,那么我们如何能确定堆内存需要分配
多少空间呢?我们需要大概计算每个对象所占的空间大小。
1 JAVA 对象内存布局
JAVA 对象在内存中主要有以下几部分:
对象头
MarkWord:一系列标记位(哈希码、分代年龄、锁状态标记等),在 64 位系统中占
8 字节。
ClassPoint:对象对应的类信息的内存地址,在 64 位系统中占 8 字节。
Length:数组对象特有,表示数组长度,占 4 字节。
实例数据
包含了对象的所有成员变量,大小由变量类型决定。
byte、boolean:1 字节
short:2 字节
char:2~3 字节
int、float:4 字节
long、double、引用数据类型:8 字节
对其填充
将对象大小填充为 8 字节的整数倍
12
2 JVM 内存溢出和垃圾回收机制
为什么要进行垃圾回收:
如果对象只创建不回收,会造成堆内存溢出(OOM)异常。
为什么要进行堆内存分区:
\1. 提高搜索垃圾的效率。
\2. 垃圾回收后可以更好的利用内存空间,存放大对象。
\3. 尽可能减少 GC 次数
3 JVM 堆内存的划分
老年代:
对象会优先分配到新生代内存中,每次 GC 后没有回收的对象年龄加 1,年龄到
15 还没有被回收,对象会存放到老年代内存中;如果对象较大,超过新生代内存的一
半,对象也会存放到老年代区域
新生代:
为了减少young区垃圾回收后的空间碎片,新生代又分为Eden区和两个Survivor
区,且始终有一个 Suvivor 区保持闲置。对象会先存放到 Eden 区当中,Eden 区空间
满了之后会进行 young 区的垃圾回收,之后将 young 区所有存活的对象复制到闲置
的 Suvivor 区中,并清空 Eden 区和正在使用的 Survivor 区。
4 YoungGC 和 OldGC
YoungGC
新生代区域的垃圾回收称之为 YoungGC,也叫 MinorGC,Eden 区满后会触发
YoungGC
OldGC
老年代区域的垃圾回收称之为 OldGC,也叫 MajorGC,OldGC 非常浪费性能,
所以我们的 JVM 调优要尽可能减少 OldGC 的次数, OldGC 往往伴随着 YoungGC。
YoungGC+OldGC = FullGC
1. Survivor 区空间并不大,如果满了怎么办?
(1)一般情况下 GC 会回收 95%的对象,且超过 15 次 GC 的对象会存放到 old
去,所以 Survivor 区不容易满。
(2)如果 Survivor 区满了,会触发担保机制,提前将对象存入 Old 区。
2. 为什么需要 Survivor 区?
为了减少垃圾回收带来的空间碎片,空间碎片过多会频繁触发 YoungGC。
3. 为什么需要两块 Survivor 区?
为了减少 Survivor 区的空间碎片
5 JVM 运行监控工具 VisualVM
打开 JAVA 安装目录/bin/jvisualvm.exe
安装 VisualGC 插件。
注:JDK9 之后需自行下载该工具
修改堆内存大小的指令
-Xms10M -Xmx10M :对象比较消耗内存,一般占用电脑本机内存1/4,如16G内存,占用4G,修改有助于明显查看
(springboot版本修改堆内存)
(一般项目版本修改堆内存)
5.1实体类
/**
* @Author yqq
* @Date 2021/5/20 21:53
* @Version 1.0
*/
public class Student {
private String name;
private String sex;
private Integer age;
}
5.2 测试类
/**
* @Author yqq
* @Date 2021/5/20 21:55
* @Version 1.0
*/
public class TestGC {
public static void main(String[] args) throws Exception{
List<Student> studentList=new ArrayList<>();
while (true){
/**
* 对象比较消耗内存,一般占用电脑本机内存1/4,如16G内存,占用4G
*/
studentList.add(new Student());
studentList.add(new Student());
studentList.add(new Student());
studentList.add(new Student());
studentList.add(new Student());
studentList.add(new Student());
Thread.sleep(1);
}
}
}
监测创建Student对象堆内存详情
由于创建对象过快,当Eden来不及回收对象时导致内存溢满报异常