一
1.对象被判定为垃圾的标准
没有被其他对象引用.
2.判定类是否无用的类的条件
1.该类的所有实例都已经被回收
2.加载该类的ClassLoader以及被回收
3.该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的所有方法。
2.对象存活判断法
1.引用计数算法
图:引用计数算法.png
![]()
图:引用计数算法优缺点.png
1.原理:给对象添加一个引用计数器,每当有一个地方引用它时,计数器就加1.当引用失效,计数器就减1.计数器为0的对象,垃圾回收器会认为该对象是可回收的。
2.分类(java1.2之后):
-------1.强引用(Strong Reference):代码中普遍存在,类似Object obj = new Object();GC用于不会回收强引用的对象。
-------2.软引用(Soft Reference):描述一些有用但并非必须的对象。在系统将要发生内存溢出之前,将会把这些对象进行第二次回收,如果回收后还没有足够的内存,才会抛出内存溢出异常。
-------3.弱引用(Weak Reference):指一些非必须的对象,强度比软引用更弱,在下一次垃圾回收的时候,无论内存是否足够,都会进行回收。
-------4.虚引用(Phantom Reference):也称为幽灵引用或者幻影引用。最弱的一种引用关系,无法通过虚引用取得一个对象实例,为一个对象设置虚引用关联的唯一目的就是能在对象被回收的时候收到一个系统通知。
2.可达性算法
图:可达性分析算法.png
1.原理:通过一系列称为GC Roots的对象作为起始点,开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象和GC Roots没有任何引用链能项链,就代表GC
Roots到这个对象是不可达的。垃圾回收器会认为该对象是可回收的。
2.哪些对象可作为GC Roots对象
图:可作为GC Root的对象
-------1.虚拟机栈中引用的对象
-------2.方法区类静态属性引用的对象
-------3.方法区常量池引用的对象
-------4.本地方法栈JNI引用的对象
3.垃圾收集算法
图:标记-清除算法.png
1.标记-清除(Mark-Sweep)
1.标记:首先进行可达性分析时发现没有与GC Roots相连,会被第一次标记,此时判断此对象如果finalize()方法被重写并且没有被虚拟机调用过,将会调用finalize()方法。执行完成后如果对象还是没有被引用,进行第二次标记。
2.清除:回收被两次标记的对象。
3.缺点:
-------1.效率:标记和清除两个过程效率都不高
-------2.空间:标记清楚后会产生大量不连续的内存碎片,可能导致以后需要给较大的对象分配空间时找不到连续的内存。
2.复制算法
图:复制算法.png
图:复制算法优点.png
原理:将内存平均分为两块,每次只使用其中一块,当这一块内存用完,就将还存活着的对象按顺序复制到另一块上,然后清理掉这一块的数据。实现简单,运行效率高。
缺点:内存缩小为了原来的一半。
注意:HotSpot虚拟机并不是按照1:1的比例来分配,因为新生代98%的对象是朝生夕死的,它将内存分为较大的Eden空间和两块较小的Survivor空间(8:1:1),每次只使用Eden和其中一块Survivor1空间。回收时,将Eden和Survivor1中存活的对象复制到另一块Survivor2空间,下次会将Eden和Survivor2中存活的对象复制到Survivor1中。当这块Survivor空间内存不够时,对象会被移入老年代。对象在Survivor 区中每熬过一次 Minor GC,年龄就增加 1 岁,当它的年龄增加到一定程度(默认为 15 岁)时,也会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。
3.标记-整理
图:标记-整理算法.png
![]()
图:标记清除算法的优点.png
1.标记:同标记清除
2.整理:让所有存活的对象都向一端移动,然后清理掉端边界意外的内存。
4.分代收集
把java堆分成新生代和老年代,不同的年代使用以上不同的算法,新生代对象死亡比较多,会使用复制算法。老年代对象存活率高,没办法多出空间进行复制算法,就必须使用标记-清除或标记-整理算法。
二
2.Gc的分类
1.MinorGC:对新生代的垃圾收集称为MinorGC
触发条件:当年轻代(Eden区)满时就会触发 Minor GC,这里的年轻代满指的是 Eden区满。Survivor 满不会触发 Minor GC 。对于大部分应用程序,Minor GC操作时应用程序停顿导致的延迟都是可以忽略不计的,因为大部分 Eden 区中的对象都能被认为是垃圾。各个收集器均支持MinorGC。
2.MajorGC:只针对 老年代的垃圾收集。 目前,只有CMS收集器会有单独收集老年代的行为,其他收集器均无此行为。
触发条件:当老年代满时会触发MajorGC
3.FullGC:清理整个堆空间。
触发条件:
图:触发Full Gc的条件.png
-------1.调用System.gc时,系统建议执行Full GC,但是不一定会执行 。
-------2.老年代空间不足。
-------3.通过 Minor GC 后进入老年代的空间大于老年代的可用内存。
-------4.内存空间担保。
2.对象如何晋升到老年代
图:对象如何晋升到老年代.png
3.常用参数调优
图:常用参数调优.png
三
1.StopTheWorld
图:StopTheWorld.png
进行GC时停顿所有java执行线程,避免GC过程中对象引用关系还在不断变化。
2.Safepoint
safepoint就是一个安全点,所有的线程执行到安全点的时候就会去检查是否需要执行safepoint操作,如果需要执行,那么所有的线程都将会等待,直到所有的线程进入safepoint。然后JVM执行相应的操作之后,所有的线程再恢复执行。
图:Safepoint.png
HotSpot中,安全点位置主要在:
1.方法返回之前
2.调用某个方法之后
3.抛出异常的位置
4.循环的末尾
3.jvm的运行模式
1.HotSpot虚拟机的Client模式和Server模式的区别
1.编译器
-------1.client模式启动的时候,使用的是一个代号为C1的轻量级编译器
-------2.server模式启动的虚拟机采用相对重量级,代号为C2的编译器.
-------3.区别:C2比C1编译器编译的相对彻底,服务起来之后,性能更高
2.区别: Client:更注重编译的速度,启动速度快,更适合用在客户端的版本下,针对GUI进行了优化 Server:更注重编译的质量,启动速度慢,但是运行效率高,适合用在服务器环境下,针对生产环境进行了优化
四
1.垃圾收集器
如果说垃圾收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。
1.新生代垃圾收集器(全部使用的 标记-清除算法)
Serial收集器
图:Serial收集器.png
单线程收集器,它在工作时,必须暂停其他所有工作线程。虚拟机Client模式下的默认年轻带收集器,简单高效。
ParNew收集器
图:ParNew收集器.png
相当于Serial的多线程版本,能与CMS配合工作。但cpu下不如Serial,多cpu下有优势。默认开启的收集线程数和cpu的数量相同,可通过-XX:ParallelGCThreads参数限制线程数。
ParallelScavenge收集器
图:ParallelScavenge收集器.png
-------1.并行的多线程收集器,比起其他尽可能缩短用户线程停顿时间的收集器,它更在乎系统的吞吐量(吞吐量=运行用户代码的时间/(运行用户代码时间+垃圾收集时间)),被成为“吞吐量优先”的收集器。高吞吐量可以高效利用cpu时间,尽快完成运算任务,适合在后台运算而不需要太多交互的任务。
-------2.虚拟机Server模式下默认的收集器,有自适应调节策略功能,如果手工调节优化存在困难的时候,可通过-XX:+UseAdaptiveSizePolicy参数打开自适应调节策略,此时虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整一些细节参数以达到最适合的停顿时间或者最大的吞吐量。
2.老年代垃圾收集器
Serial Old收集器
图:Serial Old收集器.png
Serial收集器的单线程老年代版本,使用标记-整理算法,Client模式下默认的老年代收集器。
ParallelOld收集器
图:ParallelOld收集器.png
ParallelScavenge收集器的多线程老年代版本,使用标记-整理算法。吞吐量优先的收集器。
CMS收集器(Concurrent Mark Sweep)
图:CMS收集器.png
1.以获取最短回收停顿时间为目标的收集器。非常适合B/S系统的服务端上。使用 标记-清除算法。由于最耗时并发标记和并发清除过程都能与用户线程一起工作,所以能做到低停顿。默认启动线程数为(CPU数量+3)/4
2.运行过程:
-------1.初始标记(CMS initial mark):标记GC Roots能直接关联到的对象,会发生Stop The World,但停顿时间很短。(单线程)
-------2.并发标记(CMS concurrent mark):进行GC Roots Tracing的过程,从第一阶段收集到的对象引用开始,遍历所有其他的对象引用。不会停顿用户线程。
-------3.重新标记(CMS remark):修成并发标记期间因用户现场继续运作而导致标记产生变动的那一部分对象的标记记录,会发生Stop The World,停顿时间比初始标记停顿的时间长。(多线程)
-------4.并发清除(CMS concurrent sweep):所有不再被应用的对象将从堆里清除掉。不会发生Stop The World。
-------5.并发重置:重置CMS的数据结构。
3.缺点:
-------1.无法处理浮动垃圾:CMS在并发清理的时候,用户线程继续运行会产生新的垃圾,这一部分垃圾出现在标记过程之后,因此无法在当次收集中处理,中号留在下次GC处理,这一部分垃圾称为-浮动垃圾。
-------2.因为采用标记-清除算法,虚拟机运行时间过长会导致内存碎片化,导致大对象分配时无法找到连续的内存。不得不提前触发一次FULL GC。CMS提供了-XX:+UserCMSCompactAtFullCollection开关参数(默认开启),用于在CMS顶不住要进行FullGC时开启内存碎片的合并整理过程,但是这一过程会加大Stop The World的停顿时间。
3.GarbageFirst收集器(G1)
通过把Java堆分成大小相等的多个独立区域,回收时计算出每个区域回收所获得的空间以及所需时间的经验值,根据记录两个值来判断哪个区域最具有回收价值,所以叫Garbage First(垃圾优先)。
Garbage First收集器.png
特点:
-------1.并行与并发:能充分利用多核环境下的硬件优势,使用多个cpu缩短Stop The World停顿时间。
-------2.分代收集:将整个堆划分为大小相等的Region,但还保留新生代和老年代的概念,新生代和老年代被分成了多个Region。
-------3.空间整合:G1整体上是基于 标记-整理 算法实现,局部上来看是基于 复制 算法,因此G1不会产生内存碎片,收集后能提供规整的可用内存。
运行过程:
-------1.初始标记:标记GC Roots能直接关联到的对象,会发生Stop The World停顿,时间很短。
-------2.并发标记:从GC Roots开始对堆中对象进行可达性分析,找出存活对象,耗时长,但能与用户线程并发执行。
-------3.最终标记:修正并发期间用户线程运作时导致标记产生变动的那一部分标记记录。
-------4.筛选回收:对各个Region的回收价值和成本进行排序,制定回收计划。
3.根据线程类型划分
1、单线程阶段,对应收集器:
Serial、Serial Old;
2、并行阶段,多条收集器线程,对应收集器:
ParNew、Parallel Scavenge、Parallel Old;
3、并发阶段,收集器线程与用户线程同时运行,对应收集器:
CMS(Concurrent Mark Sweep);
4、并行+并发+分区阶段,堆内存划分成多个小块进行收集,对应收集器:
G1(Garbage First);
四
1.常见面试题
ParallelOld收集器
图:ParallelOld收集器.png
java种的强引用,软引用,弱引用,虚引用
图:强引用.png
图:软引用.png
图:弱引用.png
图:虚引用.png
强、软、弱、虚表格图
图:表格图.png
2.引用队列ReferenceQueue
图:引用队列ReferenceQueue
在一个对象被垃圾回收器扫描到将要进行回收时,其相应的引用包装类,即reference对象会被放入其注册的引用队列queue中。可以从queue中获取到相应的对象信息,同时进行额外的处理。比如反向操作,数据清理,资源释放等。