垃圾回收机制(GC)
- 1 需要GC的内存区域
- 2 判断GC对象是否存活
- 3 标记死亡对象
- 4 什么时候触发GC
- 5 GC分类
- 6 GC常用算法
-
- 6.1 标记-清除算法
- 6.2 标记-压缩算法
- 6.3 复制算法
- 6.4 分代收集算法
-
- 6.4.1 标记和压缩算法存在的问题
- 6.4.2 分代收集算法思想
- 6.4.3 分代收集过程
-
- 1. 新生代(Young)分为Eden区,From区与To区
- 2. 几乎任何新的对象都会在eden空间分配内存,两个survivor空间一开始都是空的
- 3. 随着对象的不断创建,Eden区空间逐渐被填满.
- 4. 当Eden区满了,那么就会触发一次Minor GC(Young GC),也就是新生代的垃圾回收,所采用的是复制算法
- 5. 下一次minor GC发生时,Eden空间的存活对象将被复制到空闲的survivor空间S1(年龄+1),另外在前一次minor GC S0空间的存活对象也会被复制到S1(年龄+1),垃圾对象会被清除掉
- 6. 下一次minor GC发生时,还是重复第4条的内容,只是两个survivor空间对调了,这次是从S1复制到S0空间
- 7. 随着Minor GC的不断发生,幸存对象在两个幸存区不断地交换存储,年龄也不断递增。当幸存对象的年龄达到指定的阈值(这个例子中是8,由JVM参数MaxTenuringThreshold决定)后,它们将被移动到老年代
- 8. 当年老代的内存被填满的时候,将会触发将触发Major GC(Full GC)进行老年代的内存清理。Major GC在老年代用的是标记清除算法。同时新生代的对象将被清除。
- 6.5 对象被放置到老年代的五个条件
- 6.6 Full GC触发条件
- 7 方法区垃圾回收
- 8 finalize()方法
- Java GC (Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一
- 作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题。
- 自动垃圾回收是查看堆内存、识别哪些对象正在使用、哪些未使用以及删除未使用对象的过程。一个使用中的对象,或一个引用的对象,意味着你的程序的某些部分仍然维护着一个指向那个对象的指针。未使用的对象或未引用的对象不再被程序的任何部分引用。因此可以回收未被引用的对象使用的内存。
- 在像 C 这样的编程语言中,分配和释放内存是一个手动过程。在 Java 中,释放内存的过程由垃圾收集器自动处理
1 需要GC的内存区域
-
jvm 中,程序计数器、虚拟机栈、本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理
-
因此,我们的内存垃圾回收主要集中于 java 堆 和 方法区中,在程序运行期间,这部分内存的分配和使用都是动态的
2 判断GC对象是否存活
判断一个对象是否存活常用的有两种办法:引用计数和可达性分析
2.1 引用计数
每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,无法解决对象相互循环引用的问题。
Java没有选择使用引用计数算法管理内存。
2.2 可达性分析(Reachability Analysis)
从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,不可达对象。(其实就是搜寻对象是否有引用)
GC Roots包括:
- 虚拟机栈中引用的对象。
- 方法区中类静态属性实体引用的对象。
- 方法区中常量引用的对象。
- 本地方法栈中JNI引用的对象。
通过可达性分析可以对需要回收的对象进行标记,但并不意味着一定会被回收
3 标记死亡对象
要真正宣告一个对象的死亡,至少要经历两次的标记过程
3.1 第一次标记
第一次标记前提: 在可达性分析后发现到GC Roots没有任何引用链相连时,被第一次标记。并且判断此对象是否必要执行finalize()方法!
对象被回收: 如果对象没有覆盖finalize()方法或者finalize()已经被JVM调用过,则这个对象就会认为是垃圾,可以回收。
对象不被回收: 对于覆盖了finalize()方法,且finalize()方法没有被JVM调用过时,对象会被放入一个称为F-Queue的队列中,等待着被触发调用对象的finalize()方法。
3.2 第二次标记
第二次标记前提: 执行完第一次的标记后,GC将对F-Queue队列中的对象进行第二次小规模标记。也就是执行对象的finalize()方法!
对象不被回收: 如果对象在其finalize()方法中重新与引用链上任何一个对象建立关联,第二次标记时会将其移出"即将回收"的集合。
对象被回收: 如果对象没有,也可以认为对象已死,可以回收了。
4 什么时候触发GC
- 程序调用System. gc() 时可以触发
- 系统自身来决定GC触发的时机(根据Eden区和From Space区的内存大小来决定。当内存大小不足时,则会启动GC线程并停止应用线程)