`
zzc1684
  • 浏览: 1188538 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

Java虚拟机之JVM整理学习笔记(三)

    博客分类:
  • Java
阅读更多

一,判断对象存活算法
JVM如何判断对象可以回收了?
主要的算法有:
1,引用计数算法,当多一个地方引用此类时,引用计数加一,否则就减一,算法很简单,实现也比较简单
缺点:很难解决对象之间相互引用的问题

2,可达性分析算法,通过一系列GC Roots路径,从节点开始搜索,来判断整个引用链是否还有关系。
  在java语言中,可作为GC Roots的对象包括下面几种:
       虚拟机栈(栈帧中的本地变量表)中引用的对象。
       方法区类静态属性引用的对象。
       方法区中常量引用的对象。
       本地方法栈中JNI引用的对象。


二,垃圾收集算法

(1),标记-清除算法
分为标记和清楚2个节点,首先标记出所有的需要回收的对象,标记完成后统以回收,它是垃圾回收里面最基础的算法,下面其他的几个都是基于这个算法改进的,

缺点:  标记和清除两个过程效率都不高,另外清除后悔产生大量不连续的内存碎片,碎片太多会导致,分配大对象时,找不到连续内存,从而提前触发另一次垃圾垃圾收集动作


(2),复制算法
为了解决效率问题,一种叫做复制的算法出现了,它将可用内存按容量分为大小相等的两块,每次使用其中一个,当这一个内存用完了,就把存活的对象复 制到另一块上面,然后把已使用过的内存空间一次性清理掉,这样就使得每次都对半个区内存进行回收,分配时也不用考虑内存碎片等问题,只要移动堆顶指针,按 顺序分配即可,简单,高效。

缺点:将内存缩小为原来一半,比较浪费空间,现在主流的商业虚拟机,基本都采用这种算法,来回收新生代。

(3),标记-整理算法
复制收集算法在对象存活率较多的时候,要进行较多的复制操作,效率将会变低,如果不想浪费一半的空间,就需要有额外的内存分配担保,应对100% 对象都存活的极端情况,所以在老年代里面不能直接选用这种算法,根据老年代的特点,有人提出了另外一种的算法,标记-整理,过程仍与标记-清除一样,但是 后续步骤不是直接回收,而是让所有存活对象,都向一端移动,然后清理掉其他的边界外的内存,避免了空间碎片的出现。

(4),分代收集算法
当前的商业虚拟机都采用分代收集的算法,将对象存活周期划分为几块,一般是把Java堆划分为新生代和老年代,这样就可以根据各个年代的特点,采 用最适当的收集算法,在新生代中,每次垃圾收集时都有大批对象死去,只有少量存活,那就选复制算法,只需要付出少量存活对象的复制成本就可以完成收集,而 老年代中因为对象存活率高,没有额外空间对它进行分配担保,就必须使用标记-清除或标记-整理算法来回收。



下面,来看下7种用于不同分代垃圾收集器,如下图所示:(注意连线部分代表,两种收集器,可以配合使用,)







1,Serial收集器
serial收集器,是最基本,发展历史最悠久的收集器,曾经在JDK1.3之前,是虚拟机新生代的唯一收集器,这个收集器是单线程的,简单而高效,对于Client的桌面模式是一个不错的选择。

2,ParNew收集器
ParNew收集器是Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,它的控制参数包含serial所有的控制参数,正是因为它 的多线程收集优势,所以是许多运行在Server模式下的虚拟机中首选的新生代收集器,,其中一个与性能无关的重要原因是,除了Serial收集器外,目 前只有它能与CMS老年代收集器配合工作,注意,单核CPU下,建议还是使用Serial收集器。

下面解释下并发和并行的收集器的区别:
并行(Parallel):指多条垃圾收集线程并行工作,但此时其他所有的用户线程都处于等待状态
并发(Concurrent):指用户线程与与垃圾收集线程同时运行,但一定是并行,可能会交替执行,用户程序在继续,而垃圾收集程序,运行在另一个CPU上


3,Parallel Scanvenge收集器
Parallel Scanvenge收集器是一个新生代收集器,他也是使用复制算法的收集器,又是并行的多线程收集器,它的关注点和其他的的收集不同,CMS等收集器关注 点尽可能的缩短垃圾收集时用户线程的停顿时间,而Parallel Scanvenge收集器则是达到一个可控制的吞吐量,这是两种不同的应用场景。

停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,特别是在搜索类电商中,而高吞吐量则可以高效率的利用cpu时间,尽 快完成程序的计算任务,适合在后台运算,不需要太多的交互的任务,另外自适应调节策略也是Parallel Scanvenge收集器与ParNwe收集器的一个重要区别

4,Searial Old收集器
单线程的老年代的收集器,主要应用与Client模式下的虚拟机,如果放在Server模式下,还有两大用途,一作为CMS收集器的后备方案,在CMS失败时启用,另外一种是与Parallel Scavenge收集搭配使用。


5,Parallel Old收集器
Parallel Old收集器是Parallel Scavenge的老年代版本,使用多线程和标记-整理算法,在JDK1.6中才开始提供,在这之前,如果新生代选择了Parallel Scavenge收集器,老年代只能使用Serail old,Parallel Old收集器出现后,使组合方式变的更多了。


6,CMS收集器
CMS收集器是一种以获取最短回收停顿时间为目标的收集器,目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其 重视响应速度,而散仙所在的搜索组更是注重系统交互响应时间,停顿时间越短,给用户带来更快更流畅的体验,CMS就非常符合这类应用的需求,CMS采用了 标记-清除的算法实现,采取了并发的收集,举个例子,饭店的模式就非常类似,当所有的饭桌都做满人了,此时再来的客人,就需要等待别人吃完,这个时候,就 是我们收集器里面的Full GCC触发的停顿,当峰值消退,饭店就可以一边吃饭,然后一边有人离去,然后一边有人进来,而不用等所有的客人都走完了,才重新进来,那样饭店不赔死了?
CMS的优点就是,并发收集,低停顿,但是它也有自身的缺点:

(1)CMS收集器会占用一部分的CPU资源,从而可能导致吞吐率下降
(2)CMS无法清理浮动垃圾,因为是并发处理,不断标记,不断清理,不断产生垃圾,CMS无法一次性清除掉垃圾,这部分被称为浮动垃圾,如果浮 动垃圾产生的速度大于收集的速度,那么就有可能导致Concurrent Mode Failure失败,系统会临时采用Serial Old收集器,进行老年代收集,这样停顿时间就更长了。
(3)CMS的标记-清除算法,会产生大量的空间内存碎片,如果剩余的连续空间,不能够放下一个较大的对象实例时,将会触发Full Gc。

6,G1收集器
G1(JDK1.7的)收集器是当今收集器技术发展的最新成果之一,G1是一款面向服务端应用的垃圾收集器,HotSpot赋予它的使命是在未来较长时期内,可以替代掉JDK1.5中的CMS收集器
G1的特点:
(1)并行与并发:充分利用多CPU,多核环境环境下的硬件优势
(2)分代收集,采用不同的方式,收集新创建的,存活中,熬过多次的GC旧对象
(3)空间整合,采用复制拷贝垃圾回收算法,有效整理空间内存碎片
(4)可预测的停顿,建立可预测的停顿时间模型,在计划规定的时间内进行回收


最后再来看下GC日志的格式,先看下面的程序:

Java代码  收藏代码
  1. package com.test.gc;  
  2.   
  3. /* 
  4.  * -verbose:gc 、 
  5.  * -XX:+PrintGCDetails -Xloggc:../gc.log 
  6.  * 或-XX:+PrintGCDetails -Xloggc:gc.log 将GC的日志log存储到指定文件中 
  7.  *  
  8.  *  
  9.  * **/  
  10. public class GcTest {  
  11.       
  12.     public Object instance=null;  
  13.     private static final int _1MB=1024*24;  
  14.       
  15.     private byte[] bytes=new byte[2*_1MB];  
  16.       
  17.     public static void main(String[] args) {  
  18.           
  19.         for(int i=0;i<20;i++){  
  20.         GcTest g1=new GcTest();  
  21.         GcTest g2=new GcTest();  
  22.           
  23.         g1.instance=g2;  
  24.         g2.instance=g1;  
  25.         g1=null;  
  26.         g2=null;  
  27.       
  28.         }  
  29.          System.gc();  
  30.     }  
  31.   
  32. }  



GC的日志打印:

Java代码  收藏代码
  1. 0.062: [GC [PSYoungGen: 2556K->520K(38080K)] 2556K->520K(125056K), 0.0007521 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]   
  2. 0.063: [Full GC (System) [PSYoungGen: 520K->0K(38080K)] [ParOldGen: 0K->465K(86976K)] 520K->465K(125056K) [PSPermGen: 2487K->2485K(21248K)], 0.0067204 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]   
  3. Heap  
  4.  PSYoungGen      total 38080K, used 1962K [0x00000000d58b00000x00000000d83200000x0000000000000000)  
  5.   eden space 32704K, 6% used [0x00000000d58b0000,0x00000000d5a9aa28,0x00000000d78a0000)  
  6.   from space 5376K, 0% used [0x00000000d78a0000,0x00000000d78a0000,0x00000000d7de0000)  
  7.   to   space 5376K, 0% used [0x00000000d7de0000,0x00000000d7de0000,0x00000000d8320000)  
  8.  ParOldGen       total 86976K, used 465K [0x0000000080a000000x0000000085ef00000x00000000d58b0000)  
  9.   object space 86976K, 0% used [0x0000000080a00000,0x0000000080a74470,0x0000000085ef0000)  
  10.  PSPermGen       total 21248K, used 2496K [0x000000007b8000000x000000007ccc00000x0000000080a00000)  
  11.   object space 21248K, 11% used [0x000000007b800000,0x000000007ba70088,0x000000007ccc0000)  




格式详解,如下图所示:
Minor GC:



Full GC:


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics