JVM的GC

一、为什么会有GC过程

因为JVM的内存不是无限的,对于一些没有再使用的对象,需要使用垃圾收集器来处理掉这些无用对象。

二、有哪些GC的方法

总的来说,有以下三种方法:
①、标记-清除算法(Mark-Sweep)
②、复制算法(Copying),也叫停止-复制算法(Stop-Copy)
③、标记-整理算法(Mark-Compact)
新生代发生的回收叫做Minor GC,使用算法①、②,并且发生的比较频繁。
老年代发生的回收叫做Major GC/Full GC,相比于新生代的GC过程更慢,更费时,更少发生。


如果对新生代和老年代不是很理解的话,可以看看我的其他博文:https://blog.csdn.net/zj1548282042/article/details/87563778

三、有哪些对象可以被回收

满足可达性算法的对象不能被回收,换句话说,不满足这个算法的对象就是能回收的。
可达性算法:从GC Roots对象出发向下搜索,能够关联的对象,就是可达对象,即可用对象。
下图:(来源:《深入理解Java虚拟机》)
JVM的GC

那么什么对象可以作为GC Roots呢?
JVM的GC
上图中的黄色对象可以作为GC Roots
因为满足一下关系之一:
①、虚拟机栈(栈帧中的本地变量表)中引用的对象
②、方法区中类静态属性引用的对象
③、方法区中常量引用的对象
④、本地方法栈中JNI(即Native方法)引用的对象。

四、GC算法的具体过程

复制(Copying)
复制采用的方式为从根集合扫描出存活的对象,并将找到的存活的对象复制到一块新的完全未被使用的空间中,如图所示:
JVM的GC
复制收集器方式仅需要从根集合扫描所有存活对象,当要回收的空间中存活对象较少时,复制算法会比较高效(年轻代的Eden区就是采用这个算法),其带来的成本是要增加一块空的内存空间及进行对象的移动。
标记-清除(Marking-Deleting)
标记-清除采用的方式为从根集合开始扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未标记的对象,并进行清除,标记和清除过程如下图所示:
JVM的GC
上图中蓝色的部分是有被引用的存活的对象,褐色部分没被引用的可回收的对象。在marking阶段为了mark对象,所有的对象都会被扫描一遍,扫描这个过程是比较耗时的。
JVM的GC
清除阶段回收的是没有被引用的对象,存活的对象被保留。内存分配器会持有空闲空间的引用列表,当有分配请求时会查询空闲空间引用列表进行分配。
标记-清除动作不需要进行对象移动,且仅对其不存活的对象进行处理。在空间中存活对象较多的情况下较为高效,但由于标记-清除直接回收不存活对象占用的内存,因此会造成内存碎片。
标记-压缩(Mark-Compact)
标记-压缩和标记-清除一样,是对活的对象进行标记,但是在清除后的处理不一样,标记-压缩在清除对象占用的内存后,会把所有活的对象向左端空闲空间移动,然后再更新引用其对象的指针,如下图所示:
JVM的GC
很明显,标记-压缩在标记-清除的基础上对存活的对象进行了移动规整动作,解决了内存碎片问题,得到更多连续的内存空间以提高分配效率,但由于需要对对象进行移动,因此成本也比较高。
原文:https://blog.csdn.net/suifeng3051/article/details/48292193

参考:
https://blog.csdn.net/suifeng3051/article/details/48292193
《深入理解Java虚拟机》—周志明