GC针对什么对象:
当一个对象通过一系列根对象。(比如静态属性引用的常量)都不可达时就会被回收。--- 当一个对象所有引用都为null,如果对象A有一个指向对象B的引用,对象B也有一个指向对象A的引用,除此之外,它们没有其他引用,那么对象A和对象B都、需要被回收。
堆内存是如何划分的:
java中的对象都在堆上创建。为了GC,堆内存分为三个部分。新生代,年老代和永久代。
垃圾收集算法:
1、标记-清除算法:
算法分为 标记 和 清除 两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。 该算法的主要不足有两个,一个是效率问题,标记和清除两个过程的效率都不高 另一个是空间问题, 标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作;
该算法的执行过程如下图:
2、复制算法:
该算法将可用内存按容量划分为大小相等的两块,每次只使用其中的一块,当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。缺点是将内存缩小为了原来的一半。
一般新生代采用此种算法,因为新生代中的对象98%是 “朝生夕死”的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survior空间,每次使用Eden和其中一块Survivor.当会收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。Eden和survivor默认大小是8:1。
该算法的执行过程如下图:
3、标记-整理算法:
标记过程仍然与“标记-清除”算法一样 ,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
该算法的执行过程如下图:
4、分代收集算法:
当前商业虚拟机的垃圾收集都采用“分代收集”算法,这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分为几块。一般是把java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而年老代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或者就“标记-整理”算法来进行回收。
垃圾收集器:
如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。
- Serial收集器:新生代采取复制算法。这个收集器是一个单线程的收集器,但它的“单线程”的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集时,必须暂停其他所有工作线程。
- ParNew收集器:新生代采取复制算法。这个收集器其实就是Serial收集器的多线程版本。除了使用托条线程进行垃圾收集之外,其余行为包括Serial收集器可用的所有控制参数。(并行收集器)
- Parallel Scavenge收集器:新生代收集器,采用复制算法,并行多线程。吞吐量优先收集器,所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即 吞吐量 = 运行用户代码时间 / (运行用户代码时间+垃圾收集时间),虚拟机总共运行了100分钟,其中来及收集花掉1分钟,那吞吐量就是99%。-XX:MaxGCPauseMillis参数,控制最大垃圾收集停顿时间。-XX:GCTimeRatio设置吞吐量大小。-XX:+UseAdaptiveSizePolicy :这是一个开关参数,当这个参数打开后,就不需要手工指定新生代的大小(-Xmn)、Eden与Survivor的比例、晋升老年代对象大小等细节参数。虚拟机会根据当前系统的运行情况动态调整这些参数。(并行收集器)
- Serial Old 收集器:老年代收集器,采用标记-整理算法。单线程收集器,其他工作线程暂停。
- Parallel Old 收集器:Parallel Scavenge收集器的老年代版本。使用多线程和“标记-整理算法”。仍要暂停其他工作线程。(并行收集器)
- CMS 收集器:(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器; 采用“标记-清除”算法,优点是 并发收集器。它的运作过程相对于前面几种收集器来说更复杂一些,整个过程分为4个步骤:
1、初始标记
2、并发标记
3、重新标记
4、并发清除
其中,初始标记和重新标记仍然需要暂停其他工作线程。由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户工作线程一起工作,所以垃圾回收是并发执行的。
概念:
并行:指多条垃圾收集线程并行工作,蛋此时用户线程仍然处于等待状态。
并发:值用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。
垃圾收集器参数总结:
参数 | 描述 |
UseSerialGC | 虚拟机运行在Client模式下的默认值,打开此开关后,使用Serial + Serial Old的收集器组合进行内存回收 |
UseParNewGC | 打开此开关后,使用ParNew + Serial Old 的收集器组合进行内存回收 |
UseConcMarkSweepGC | 打开此开关后,使用ParNew + CMS + Serial Old 的收集器组合进行内存回收。Serail Old收集器将作为CMS收集器出现Concurrent Mode Failure失败后的后背收集器使用 |
UseParallelGC | 虚拟机运行在Server模式下的默认值,打开此开关后,使用Parallel Scavenge + Serial Old 的收集器组合进行内存回收 |
UseParallelOldGC | 打开此开关后,使用Parallel Scavenge + Parallel Old 的收集器组合进行内存回收 |
SurvivorRatio | 新生代中Eden区域与Survivor区域的容量壁纸,默认为8,代码Eden : Survivor = 8 : 1 |
PretenureSizeThreshold | 直接晋升到老年代的对象大小,设置这个参数后,大于这个参数的对象将直接在老年代分配 |
MaxTenuringThreshold | 晋升到老年代的对象年龄,每个对象在坚持过一次Minor GC之后,年龄就会增加1,当超过这个参数值时就进入到老年代 |
UseAdaptiveSizePolicy | 动态调整Java堆中哥哥区域的大小以及进入老年代的年龄 |
HandlePromotionFailure | 是否允许分配担保失败,即老年代的剩余空间不足以应付新生代的整个Eden和Survivor区的所有对象都存活的极端情况 |
ParallelGCThreads | 设置并行GC时进行内存回收的线程数 |
GCTimeRation | GC时间占总时间的比率,默认值为99,允许1%的GC时间,仅在使用Parallel Scavenge 收集器时生效 |
MaxGCpauseMillis | 设置GC的最大停顿时间,仅在使用Parallel Scavenge收集器时生效 |
CMSInitiatingOccupancyFraction | 设置CMS收集器在年老代空间被使用多少后出发垃圾收集,默认值为68%,尽在使用CMS收集器时生效 |
UseCMSCompactAtFullCollection | 设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理。仅使用CMS收集器时生效 |
CMSFullGCsBeforeCompaction | 设置CMS收集器在进行若干次垃圾收集后再启动一次内存碎片整理。仅在使用CMS收集器时生效 |