当前位置: 首页 > 后端技术 > Java

JVM-GC垃圾回收机制

时间:2023-04-01 14:02:17 Java

学习JVM垃圾回收机制主要学习以下几点:哪些内存需要回收(判断对象是否可以回收),什么时候回收(GC执行时),如何回收recycle(garbagecollectionalgorithm,garbagecollection)device),垃圾回收过程。JVMGC回收哪些区域的垃圾?JVMGC只回收堆区和方法区的对象,不回收虚拟机栈中的数据。栈中的数据在超出作用域后会被JVM自动释放。因为JVMGC回收的是堆区的对象,所以先了解一下堆内存的结构图:堆内存分为新生代(YoungGeneration)和老年代(OldGeneration)。新生代和老年代占用的空间比例默认为1。:2。新生代分为Eden区和Survivor区,Survivor区由FormSpace和ToSpace组成。Eden区占用容量大,Survivor区占用容量小。默认比例为8:1:1。From和To主要是为了解决内存碎片。JVMGC是如何判断对象可以被回收的呢?对象没有引用。范围内发生未捕获的异常。程序在作用域内正常执行完毕。程序执行System.exit()。程序意外终止(终止进程等)。判断一个对象是否可以被回收涉及到垃圾回收算法,后面我们会详细讲解。有时我们可以将相关对象设置为null来尝试显式清除缓存,但是设置null并不一定能标记为可回收,比如下面的代码:publicstaticvoidtestGC(){ReferenceCountingGCobjB=newReferenceCountingGC();objA.instance=objB;objB.instance=objA;对象=空;objB=空;//假设GC发生在这一行,objA和objB是否可以被回收?系统.gc();}将objA和objB设置为null不会被标记为可回收,因为objA和objB循环依赖引用关系,但是System.gc();会进行FullGC回收。将对象设置为null至少没有坏处,但是System.gc();不可取,因为在使用System.gc();时GC操作不会立即执行,而是会等待一段时间,甚至不执行,如果执行了就会触发FullGC,对性能影响很大。JVMGC什么时候执行?当Eden区没有足够空间存放对象时,就会执行MinroGC。当提升到老年代的对象大于老年代剩余空间时,执行FullGC,小于时,通过HandlePromotionFailure参数强制FullGC。JVMGC调优主要是为了减少fullGC的触发次数。可以通过设置参数NewRatio来控制新生代和老年代的内存比例,通过设置参数MaxTenuringThreshold来改变对象进入老年代的阈值。FullGC对性能的消耗很大,执行时间是MinroGC的10倍左右。JVMGC的分代垃圾回收机制YoungGeneration:大部分新创建的对象都分配在YoungGeneration(如果对象很大,可能会分配在OldGeneration)。YoungGeneration触发GC对象被回收的过程称为MinorGC。老年代:对象在年轻代周期中存活下来,将被复制到老年代。老年代触发GC对象回收的过程称为FullGC。PersistentGeneration:也叫方法区,用来存放类加载信息、常量、静态变量等。方法区不用来存放老年代存活下来的对象,GC也可能发生在这个区域。方法区GC的过程称为MajorGC,方法区GC的条件非常严格,回收前必须满足以下三个条件:所有实例都被回收。加载该类的ClassLoader被回收。无法通过任务方法(包括反射)访问类对象。老年代如何解决引用年轻代对象的问题?老年代有一张卡表,大小为512字节,用来存放老年代对象的所有引用,以执行年轻代中的对象。查询整个老年代。在垃圾回收过程中,大部分新创建的对象都会存放在年轻代的伊甸园区。当Eden区空间不足时,会执行GC,将第一次GC后存活的对象移至Survivor的From区。之后,每次Eden区执行GC,都会将存活的对象存放到From区。当From区域饱和时,存活的对象会被移动到To区域,然后From区域会被清空。重复上述步骤N次后(N=MaxTenuringThreshold年龄阈值默认15),存活的对象将被移至老年代。如果此时老年代没有空间,就会触发FullGC。如果触发FullGC后空间仍然不足,则会抛出OOM异常。JVMGC核心参数-XX:NewRatio–XX:SurvivorRatio–XX:NewSize–XX:MaxNewSize-XX:NewRatio表示新生代和老年代的相对比例,例如-XX:NewRatio=2表示老年代是新生代的2倍,老年代占堆的2/3,新生代占1/3。-XX:SurvivorRatio表示年轻代中Eden区与Survivor区的比例。例如-XX:SurvivorRatio=8表示Eden:From:To=8:1:1。SurvivorRatio不能设置太大或太小,一般默认值就足够了。-XX:NewSize表示新生代的初始化大小。-XX:MaxNewSize表示新生代的最大大小。JVMGC算法寻根算法程序将所有的引用关系看成一棵树,从一个根节点GCROOT开始寻找对应的引用节点,找到该节点后继续寻找该节点的引用节点。搜索完所有节点后,没有被引用的节点就是无用节点。上图中红色的是无用节点,可以回收。目前Java中可以作为GCROOT的对象包括:虚拟机栈和本地方法栈中引用的对象,对象分别是局部变量表和Native对象。方法区中静态变量和常量引用的对象。mark-clear算法mark-clear算法从根集合开始扫描,对存活的对象进行标记,标记后在整个空间中扫描未标记的对象进行回收。mark-clear算法不需要移动对象,只回收非存活对象。当有很多幸存的对象时,它非常有效。但是由于mark-clear算法是直接回收非存活对象,所以没有还活着的对象。对象进行了碎片整理,因此会产生内存碎片。复制算法复制算法将内存空间划分为两个区间,所有对象只会分配到其中一个活跃区间,而另一个区间是空闲的。复制算法使用从根集合扫描将幸存的对象复制到空闲空间。扫描完成后,活动空间将被一次性回收。此时,原来的空闲空间变成了活动空间,在下一次GC操作中会重复这一过程。当存活对象相对较少时,复制算法非常有效。Mark-SortingAlgorithm标记排序算法使用与标记清除算法相同的方法来标记和回收对象,但在回收非存活对象所占用的空间后,会将所有存活对象向左移动并更新相应的对象指针。解决了内存碎片问题。为了优化内存回收,JVM使用了分代回收的方法。新生代内存回收采用复制算法,老年代内存回收多采用标记排序算法。GarbagecollectorYounggenerationcollector序号:Algorithm:Copyalgorithm描述:简单高效的单核机,默认Client模式下的younggenerationcollector。ParNew算法:Copy算法说明:Serial的多线程版本,运行在Server模式下的JVM首选的新生代收集器。ParallelScavengeAlgorithm:ReplicationAlgorithm描述:又称为吞吐量优先收集器,类似于ParNew收集器,目标是实现可控的吞吐量。SerialOldAlgorithm:Mark-Collat??ingAlgorithm描述:性能一般,单线程版本,在JDK1.5及更早版本中与ParallelScavenge收集器配合使用,作为CMS收集器的备份计划。ParallelOldAlgorithm:Mark-Collat??ingAlgorithm描述:GC多线程并行,以取代SerialOld并与ParallelScavenge一起使用。CMS算法:Mark-ClearAlgorithm说明:对CPU资源敏感,停顿时间长。会产生内存碎片,可以通过参数开启碎片整理和碎片整理。基本被G1取代。新生代和老年代共享收集器G1算法:mark-sortingalgorithm说明:新的垃圾收集器可以回收新生代和老年代。适用于多核大内存机器,GC多线程并行执行,暂停低,回收率高。