堆
堆主要的作用是给对象分配空间并且存放对象的实例,同时堆是垃圾回收的主要区域,又被称为gc堆
从垃圾回收的角度,堆被分为新生代(minor gc或者younggc)和老年代(major gc或者full gc)
从内存分配的角度看,eden将会划分出一小块空间,用作本地线程分配缓冲区(tlab),每个线程都有自己的tlab,当对象比较小时,直接可以使用tlab给对象分配内存,如果tlab不够,考虑用eden分配,eden不够则直接进入老年代
堆的结构
堆分区主要是因为大多数对象存活的时间短,优化gc的能力
- eden区(新生代):里面又分为 from survivor 和 to survivor,默认比例是8:1:1
- 老年代:新生代与老年代的比例是1:2
- 永久代: 永久代指的是方法区
1.8后去除掉了永久代的概念,也就是方法区,使用元空间(直接内存)
堆的内存分配过程
最开始应该使用线程分配缓冲区(tlab)来给对象分配空间,每个线程都有一个tlab,它可以保证线程的安全
使用tlab分配空间失败时考虑通过加锁的方式(多线程),在eden区分配空间,如果eden区满了,就会触发一次minor gc,它会清除掉没有用的对象,判断一个对象是否能被搜集通常有两种算法:引用计数器法、可达性分析法;存活下来的对象将会进入eden的from区,然后清空eden区
当eden区,会第二次触发minor gc,他会将eden存活下来的对象放入to区,from存活下来的对象年龄+1后也进入to区,然后清空eden区和from区
当eden区再次满时,第三次执行minor gc,这一次eden区存活下来的对象进入from区,to区存活下来的对象年龄+1也会进入from区,然后清空eden区和to区
随着对象的数量增加,不停的做上面两次操作,到对象的年龄到达老年带所规定的年龄阈值的时候,对象从新生代进入老年代
随着对象增加,老年代满时会执行major gc操作,gc后对象仍然无法保存报内存溢出
System.gc()会触发major gc执行
老年代满时会触发major gc执行