1.垃圾收集算法
1)引用计数法。
对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器加1,当引用失效时,A的引用计数器减1。只要对象A的引用计数器值为0,则对象A就不能再被引用了。
但是引用计数器无法处理循环引用的问题,所以JVM不使用引用计数法进行垃圾回收。
[img]http://dl2.iteye.com/upload/attachment/0105/8154/2d8f187f-67ae-3c69-a628-d46705a1a4b1.jpg[/img]
2)标记-清除算法
分为两个阶段:标记阶段和清除阶段。标记阶段从根节点标记所有可达对象。清除阶段清除所有未被标记的对象。
[img]http://dl2.iteye.com/upload/attachment/0105/8156/12ab99c4-f0bb-36e4-8e55-41a8e63e726d.jpg[/img]
标记-清除算法,回收后内存空间是不连续的。
3)复制算法
将内存空间分为2块,每次只使用其中一块,在垃圾回收时,将正使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块的所有对象,交换两个内存的角色。
[img]http://dl2.iteye.com/upload/attachment/0105/8158/2ee99520-c3a7-304d-bfa0-ced032cda54e.jpg[/img]
复制算法适用于新生代垃圾收集,因为新生代大部分对象都是垃圾对象,所以采用复制算法效率比较高。
复制算法的代价是内存被减少了一半。
4)标记-压缩算法
标记-压缩算法和标记-清除算法类似,但是它并不是简单的清除垃圾对象,而是将存活对象都压缩到内存的一端。
标记-压缩算法避免了内存碎片的产生。
[img]http://dl2.iteye.com/upload/attachment/0105/8160/5b241a06-5a1e-3ab4-9142-8ead3239b58c.jpg[/img]
由于老年代大部分是存活对象,所以不适合复制算法,而比较适合此算法。
以上各种算法,以及下面将介绍的垃圾收集器没有一个放之四海而皆准的,只有适合不适合,每个都有适合的场景,否则其他算法和垃圾收集器也就没有存在的必要了。
2.垃圾收集器
大部分垃圾收集器,垃圾回收过程中,应用软件处于stop-the-world状态,即应用程序的所有线程挂起,暂停一切工作,等待垃圾收集完成。
1)串行收集器。
有2个特点:a.使用单线程进行垃圾收集。 b.它是独占式垃圾收集。
[img]http://dl2.iteye.com/upload/attachment/0105/8162/0f15939a-d229-3bc1-9a33-8b912248cd7d.jpg[/img]
适用于单CPU和内存较小的硬件平台。
2)并行收集器
它将串行收集器多线程化,从而提高垃圾收集速度。
[img]http://dl2.iteye.com/upload/attachment/0105/8164/9a9cb0c7-14b1-331d-b7e9-480c90a06045.jpg[/img]
并行收集器主要关注系统的吞吐量。
3)CMS收集器
CMS是Concurrent Mark Sweep的缩写,意为:并发标记清除。
[img]http://dl2.iteye.com/upload/attachment/0105/8166/988b8d58-f734-3eff-9c49-21280d235a6a.jpg[/img]
它分为初始标记、并发标记、重新标记、并发清理、并发重置5个阶段,其中初始标记和重新标记阶段是独占系统资源的,其他阶段可以和用户线程一起执行。
CMS收集器由于采用标记-清除算法,因此会造成内存碎片化,如果回收到足够的空间之前,老年代满了,就会退而求其次,使用代价昂贵的stop-the-world方式进行空间压缩。
CMS收集器由于在标记时,垃圾收集和用户程序交替执行,因此用户程序会继续分配内存,所以CMS垃圾收集器需要更大的堆。
CMS收集器主要关注响应性,它减少了延迟,同时也降低了吞吐量,因为整体的垃圾收集时间被延长了。
3.并行和并发
系统有多个CPU,可以同时执行多个线程称为并行。多个应用程序同时交替运行称为并发。因此单CPU也可以并发,但是不能并行。
4.GC日志
开启-verbose:gc或者-XX:+PrintGCDetails将打印GC日志。
1)GC
[GC [PSYoungGen: 24201K->1952K(28288K)] 24201K->1952K(92928K), 0.0029127 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
标签GC 说明这是一个Minor GC,PSYoungGen说明新生代使用的是多线程垃圾收集器Parallel Scavenge(-XX:+UseParallelGC或者-XX:+UseParallelOldGC).
->左边的24201k是垃圾收集前新生代的占用量,->右边的1952k是新生代垃圾收集后的占用量。由于新生代进一步分为Eden和2块Survivor,因为Minor GC后Eden为空,所以此处的1952k也是Surivor的占用量。括号中的28288k是新生代容量的总和。
24201K->1952K(92928K)是垃圾收集前后Java堆的使用情况。->左边的24201k是垃圾收集前Java堆的占用量,->右边的1952k是垃圾收集后Java堆的占用量。括号中的92928k是Java堆的总量(新生代+老年代)。0.0029127 secs是垃圾收集花费的时间。
[Times: user=0.00 sys=0.00, real=0.00 secs]是CPU的使用时间。
2)Full GC
[Full GC (System) [PSYoungGen: 1632K->0K(11968K)] [PSOldGen: 2141K->3524K(27328K)] 3773K->3524K(39296K) [PSPermGen: 17590K->17590K(35712K)], 0.0457642 secs] [Times: user=0.05 sys=0.00, real=0.05 secs]
Full GC说明这是一个Full GC垃圾收集,PSOldGen说明是老年代垃圾收集,->左边的2141K是垃圾收集前老年代的占用量,->之后的3524k是垃圾收集后老年代的占用量,占用量有增加说明有些对象从新生代晋升到了老年代,括号内的27328K是老年代的总占用量。其余同Minor GC。PSPermGen指的是永久代。
3)Full GC (System)
[Full GC (System) [PSYoungGen: 1648K->0K(11968K)] [PSOldGen: 2217K->3560K(27328K)] 3865K->3560K(39296K) [PSPermGen: 17590K->17590K(35712K)], 0.0578854 secs] [Times: user=0.06 sys=0.00, real=0.06 secs]
Full GC之后的(System)表明是System.gc()导致的Full GC。
5.各种垃圾收集器的GC日志
1)-XX:+UseSerialGC
新生代:DefNew
老年代:Tenured
永久代:Perm
2)-XX:+UseParNewGC
新生代:ParNew
老年代:Tenured
永久代:Perm
3)-XX:+UseParallelGC
新生代:PSYoungGen
老年代:PSOldGen
永久代:PSPermGen
4)-XX:+UseParallelOldGC
新生代:PSYoungGen
老年代:ParOldGen
永久代:PSPermGen
5)-XX:+UseConcMarkSweepGC
新生代:ParNew
老年代:CMS
永久代:CMS Perm
参考资料:
1.葛一鸣《Java性能优化》
2.《Java性能优化权威指南》
1)引用计数法。
对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器加1,当引用失效时,A的引用计数器减1。只要对象A的引用计数器值为0,则对象A就不能再被引用了。
但是引用计数器无法处理循环引用的问题,所以JVM不使用引用计数法进行垃圾回收。
[img]http://dl2.iteye.com/upload/attachment/0105/8154/2d8f187f-67ae-3c69-a628-d46705a1a4b1.jpg[/img]
2)标记-清除算法
分为两个阶段:标记阶段和清除阶段。标记阶段从根节点标记所有可达对象。清除阶段清除所有未被标记的对象。
[img]http://dl2.iteye.com/upload/attachment/0105/8156/12ab99c4-f0bb-36e4-8e55-41a8e63e726d.jpg[/img]
标记-清除算法,回收后内存空间是不连续的。
3)复制算法
将内存空间分为2块,每次只使用其中一块,在垃圾回收时,将正使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块的所有对象,交换两个内存的角色。
[img]http://dl2.iteye.com/upload/attachment/0105/8158/2ee99520-c3a7-304d-bfa0-ced032cda54e.jpg[/img]
复制算法适用于新生代垃圾收集,因为新生代大部分对象都是垃圾对象,所以采用复制算法效率比较高。
复制算法的代价是内存被减少了一半。
4)标记-压缩算法
标记-压缩算法和标记-清除算法类似,但是它并不是简单的清除垃圾对象,而是将存活对象都压缩到内存的一端。
标记-压缩算法避免了内存碎片的产生。
[img]http://dl2.iteye.com/upload/attachment/0105/8160/5b241a06-5a1e-3ab4-9142-8ead3239b58c.jpg[/img]
由于老年代大部分是存活对象,所以不适合复制算法,而比较适合此算法。
以上各种算法,以及下面将介绍的垃圾收集器没有一个放之四海而皆准的,只有适合不适合,每个都有适合的场景,否则其他算法和垃圾收集器也就没有存在的必要了。
2.垃圾收集器
大部分垃圾收集器,垃圾回收过程中,应用软件处于stop-the-world状态,即应用程序的所有线程挂起,暂停一切工作,等待垃圾收集完成。
1)串行收集器。
有2个特点:a.使用单线程进行垃圾收集。 b.它是独占式垃圾收集。
[img]http://dl2.iteye.com/upload/attachment/0105/8162/0f15939a-d229-3bc1-9a33-8b912248cd7d.jpg[/img]
适用于单CPU和内存较小的硬件平台。
2)并行收集器
它将串行收集器多线程化,从而提高垃圾收集速度。
[img]http://dl2.iteye.com/upload/attachment/0105/8164/9a9cb0c7-14b1-331d-b7e9-480c90a06045.jpg[/img]
并行收集器主要关注系统的吞吐量。
3)CMS收集器
CMS是Concurrent Mark Sweep的缩写,意为:并发标记清除。
[img]http://dl2.iteye.com/upload/attachment/0105/8166/988b8d58-f734-3eff-9c49-21280d235a6a.jpg[/img]
它分为初始标记、并发标记、重新标记、并发清理、并发重置5个阶段,其中初始标记和重新标记阶段是独占系统资源的,其他阶段可以和用户线程一起执行。
CMS收集器由于采用标记-清除算法,因此会造成内存碎片化,如果回收到足够的空间之前,老年代满了,就会退而求其次,使用代价昂贵的stop-the-world方式进行空间压缩。
CMS收集器由于在标记时,垃圾收集和用户程序交替执行,因此用户程序会继续分配内存,所以CMS垃圾收集器需要更大的堆。
CMS收集器主要关注响应性,它减少了延迟,同时也降低了吞吐量,因为整体的垃圾收集时间被延长了。
3.并行和并发
系统有多个CPU,可以同时执行多个线程称为并行。多个应用程序同时交替运行称为并发。因此单CPU也可以并发,但是不能并行。
4.GC日志
开启-verbose:gc或者-XX:+PrintGCDetails将打印GC日志。
1)GC
[GC [PSYoungGen: 24201K->1952K(28288K)] 24201K->1952K(92928K), 0.0029127 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
标签GC 说明这是一个Minor GC,PSYoungGen说明新生代使用的是多线程垃圾收集器Parallel Scavenge(-XX:+UseParallelGC或者-XX:+UseParallelOldGC).
->左边的24201k是垃圾收集前新生代的占用量,->右边的1952k是新生代垃圾收集后的占用量。由于新生代进一步分为Eden和2块Survivor,因为Minor GC后Eden为空,所以此处的1952k也是Surivor的占用量。括号中的28288k是新生代容量的总和。
24201K->1952K(92928K)是垃圾收集前后Java堆的使用情况。->左边的24201k是垃圾收集前Java堆的占用量,->右边的1952k是垃圾收集后Java堆的占用量。括号中的92928k是Java堆的总量(新生代+老年代)。0.0029127 secs是垃圾收集花费的时间。
[Times: user=0.00 sys=0.00, real=0.00 secs]是CPU的使用时间。
2)Full GC
[Full GC (System) [PSYoungGen: 1632K->0K(11968K)] [PSOldGen: 2141K->3524K(27328K)] 3773K->3524K(39296K) [PSPermGen: 17590K->17590K(35712K)], 0.0457642 secs] [Times: user=0.05 sys=0.00, real=0.05 secs]
Full GC说明这是一个Full GC垃圾收集,PSOldGen说明是老年代垃圾收集,->左边的2141K是垃圾收集前老年代的占用量,->之后的3524k是垃圾收集后老年代的占用量,占用量有增加说明有些对象从新生代晋升到了老年代,括号内的27328K是老年代的总占用量。其余同Minor GC。PSPermGen指的是永久代。
3)Full GC (System)
[Full GC (System) [PSYoungGen: 1648K->0K(11968K)] [PSOldGen: 2217K->3560K(27328K)] 3865K->3560K(39296K) [PSPermGen: 17590K->17590K(35712K)], 0.0578854 secs] [Times: user=0.06 sys=0.00, real=0.06 secs]
Full GC之后的(System)表明是System.gc()导致的Full GC。
5.各种垃圾收集器的GC日志
1)-XX:+UseSerialGC
新生代:DefNew
老年代:Tenured
永久代:Perm
2)-XX:+UseParNewGC
新生代:ParNew
老年代:Tenured
永久代:Perm
3)-XX:+UseParallelGC
新生代:PSYoungGen
老年代:PSOldGen
永久代:PSPermGen
4)-XX:+UseParallelOldGC
新生代:PSYoungGen
老年代:ParOldGen
永久代:PSPermGen
5)-XX:+UseConcMarkSweepGC
新生代:ParNew
老年代:CMS
永久代:CMS Perm
参考资料:
1.葛一鸣《Java性能优化》
2.《Java性能优化权威指南》