大家好,我是七喵宅,一个分享技术和生活的博主。以下是我的主页。各首页同步更新优质博客。请关注掘金主页、知乎主页、Segmentfault主页、开源中国主页,还有更多MySQL、Redis、并发、JVM、分布式等面试热点知识,以及Java学习路线、面试重点、职业规划、面子-面面心得等内容稍后发布转载相关博文,转载请注明出处!一、如何判断对象死了1.1引用计数法给对象加上一个引用计数器。每当有对该对象的引用时,计数器值为+1,当引用无效时,计数器值为-1。当计数器为0时,说明对象已经死了,但是会出现下面的问题。Obj1=null后,Obj2=null,因为两个对象仍然互相引用,所以不能清除两个对象。1.2可达性分析'GCRoots'对象作为起点,通过引用链到达下一个对象。当一个对象在没有任何引用链的情况下连接到GCRoots时,意味着该对象是不可达的。可以作为GCRoots对象栈帧中局部变量表引用的对象局部。方法栈中JNI引用的静态属性引用的对象和对象常量引用的对象可达性分析要求整个过程基于一个能保证一致性的快照。在此快照中,遍历了对象图。StopTheduringreachabilityanalysisWorld,easilysatisfied但如果用户线程与可达性分析并发,那么有两种解决方案增量更新-CMS使用原始快照-G1使用2.条件可达性分析对象被回收的地方,对象如果有没有引用链连接到GCRoots,将执行以下操作。如果对象还没有执行finalize()方法,就会被放入F-Queue。当GC被触发时,Finalizer线程会finalize()方法执行finalize()方法,会再次判断对象是否可达,不可达则回收(这样对象可以通过连接自救自己到finalize()中的一个GCRoot链)3.垃圾收集算法标记-清除算法将标记要清除的对象。当GC被触发时,被标记的对象会被回收(存活的对象也可以反向标记)。缺点执行效率不稳定,不可移动,不需要移动对象,但会造成内存空间的碎片化。mark-copy算法(新一代JVM使用)将内存空间分成两块,每次只使用一块。将对象复制到另一个内存块,然后清除内存块。JVM新生代使用的复制算法,空间利用率低,因为大部分新生代都活不过第一轮GC,所以不需要1:1划分内存空间JVM新生代第一代使用复制算法,但在新生代中,内存空间被分为三个内存空间:Eden+Survivor1+Survivor2(8:1:1),每次只使用Eden和一个Survivor。当Eden空间不足时,触发GC,将Eden中的存活对象和使用过的Survivor复制到另一块Survivor中(如果存活对象Survivor放不下,则多余的对象进入老年代),然后清除Eden和使用幸存者Survivor的缺点当对象存活率高时,需要进行更多的拷贝,效率降低——不适用于老年代空间利用率低的情况。清除缺陷标记的剩余部分——排序算法是移动的,需要移动幸存的对象。当移动幸存对象时,用户应用程序线程(StopTheWorld)分代算法(由JVM使用)必须为整个过程暂停,不同的代使用不同的垃圾收集算法。新生代——每次GC都会有大量对象死亡,老年代采用上面的复制算法——对象存活率高,采用上面的mark-sort算法永久代,jdk1.8废除了永久generation)待回收的永久代——废弃的常量和未使用的类(Class对象)判断废弃常量一般是判断没有引用常量来判断不再使用的类,必须满足以下3个条件该类的所有实例havebeenrecycled加载该类的ClassLoader已被回收该类的Class对象没有被引用4.引用类型强引用likeObjectobj=newObject();Created如果强引用没有设置为null,它指向的对象将不会被回收。只要GC被触发,幻象引用就会被回收。PhantomReference类实现虚引用。对象的实例不能通过幻象引用获得。为对象设置幻影引用关联的唯一目的是在对象被收集器回收时收到系统通知。5.垃圾收集器5.1新一代垃圾收集器5.1.1串行单线程收集器,只用一个GC线程完成垃圾收集工作,进行垃圾收集时必须StopTheWorld。mark-copy算法使用场景Client5.1.2ParNewSerial模式的多线程版本虚拟机,使用多个GC线程完成垃圾回收工作。垃圾回收时会停止世界,使用标记-复制算法工作在服务器模式。只有ParNew可以与CMS配合使用5.1.3ParallelScavenge并行多线程垃圾处理器会触发StopTheWorld使用类似于ParNew的mark-copy算法,不同的是parallelScavenge可以采用GC自适应策略。这个收集器的目标是达到一个可控的Throughput,throughput=runningusercodetime/(runningusercodetime+garbagecollectiontime)ParallelScavenge收集器使用2个参数来控制throughputXX:MaxGCPauseMillis:控制最大垃圾收集暂停时间XX:GCRatio:SetthroughputdirectlyVolumesizeParallelScavenge还提供了第三个参数--XX:UseAdaptiveSizePolicy,启用GC自适应调整策略后,启用该参数后,无需手动指定新生代大小等细节,eden和survivor的比例等,只需要设置堆大小,最大垃圾收集时间和吞吐量大小,虚拟机根据系统运行情况动态调整这些参数2ParallelOldParallelScavenge老年代版本使用mark-sorting算法5.2.3CMSConcurrentMarkSweep使用mark-clear算法工作流程:①初始标记:(导致StopTheWorld)标记与GCRoots直接相关的对象,速度非常快②并发标记:(不会造成StopTheWorld,与用户线程并发)从GCRoots直接关联的对象开始,进行可达性分析(使用增量更新算法),开始遍历整个对象图,耗时较长③重新标记:(CausesStopTheWorld)在并发标记期间,用户程序继续运行,这可能会导致某些对象重新标记的目的是纠正这些对象的标记记录。④并发清除:(不会导致StopTheWorld)清除标记为死亡的对象。由于存活的对象不会被移动,用户线程不必挂起缺陷对处理服务器资源非常敏感,会占用一部分处理器资源,导致应用程序变慢。CMS默认启动的回收线程数=(处理器核心数+3)/4ConcurrentModeFailure——当CMS进行GC时,大多数时候用户线程要继续运行,必须预留足够的内存空间在老年代供用户线程使用。因此,CMS在老年代内存空间用完后才开始GC,而是在老年代内存空间使用到一定比例时才开始GC。会出现一种情况,当CMS开始GC时,预留内存比较少,但是在CMS执行GC的过程中,用户线程继续执行,耗尽了预留内存,就会出现并发失败(ConcurrentModeFailure),此时JVM会在老年代临时启动SerialOld收集器进行垃圾回收,并会停止world解决方案——设置两个参数,让老年代的内存空间使用率超过一定百分比,启动GCPromotionFailed-MinorGC时,Survivor空间不足,只能在老年代放置对象,此时无法放置老年代,大部分是因为老年代有足够的空闲空间,但是由于分片较多,新生代需要转移老年代区的对象比较大,找不到连续的区域来存放这个对象。因此,CMS采用mark-clear算法,会产生大量的空间碎片。在n次FullGC后压缩内存。5.3GarbageFirst(G1)5.3.1G1的特点回收范围是整个Java堆G1RegionG1是基于Region的堆内存布局,将堆分成多个大小相同的Region(默认有2048个)每个Region可以根据需要扮演4个角色——新生代Eden、Survivor、老年代、Humongous、G1收集器对扮演不同角色的Region采取不同的策略来应对每个Region。分为2部分——已分配和未分配,它们之间的分界线是top将一个对象分配给Region,只需要增加top值Region是单次回收的最小单位,每次回收的内存空间都是region大小的整数倍对于超过Region容量一半的大对象,会存储在N个连续的HumongousRegion中。整体上,使用mark-sort算法,局部(2个Region),使用mark-sort算法。复制算法不会产生内存碎片。在StopTheWorld的基础上建立了一个可预测的停顿时间模型。用户可以指定想要的暂停时间,G1会把暂停时间控制在用户设置的暂停时间内(单个STW默认最大200ms)当其他垃圾收集器触发GC时,目标是完全回收负责的区域,但是G1在进行垃圾回收时,只追求在有限的时间内回收尽可能多的垃圾(STW时间不会太长)5.3.2G1的处理思路是让G1根据回收每个region所获得的空间大小和回收所需要的时间来维护一个优先级列表。每次根据用户设置的允许采集暂停时间,按照用户的期望优先回收收益最大的Region。GC暂停时间回收(可通过参数设置,G1会在指定时间内尽可能回收垃圾)MinorGC——如果eden和survivor占用的内存超过整个堆的60%,则触发MinorGC,onlyforedenandsurvivorrecycleFullGC——如果老年代超过堆的45%,则进行一次FullGC回收新生代和老年代。G1会使用SATB记录与用户线程并发存活对象的快照并发标记,从GCRoots进行可达性分析,寻找存活对象。在此期间,用户线程可能修改了原来的引用,因此需要检查存活的对象并检查是否一致,如果不一致,扫描对象图后,重新处理SATB记录的有引用变化的对象在并发期间,最后标记StopTheWorld,并处理那些在并发标记阶段发生变化的对象。过滤回收StopTheWorld,多个收集器线程并行完成更新Region的统计数据,对每个Region的回收价值和成本进行排序,并根据用户预期的停顿时间制定回收计划。可以自由选择任意数量的Region组成一个回收集合,然后把回收值的那部分Region的存活对象复制到空Region中,然后清理oldRegion中的所有空间
