jvm 垃圾判定与垃圾回收器

简介: 任何对象都有它的生命周期,所以jvm需要定时地回收掉不用的内存,防止内存耗完。GC的时候必须暂停所有的java线程,不可以出现在分析过程中对象引用关系还在不停变化的情况。否则分析结果的准确性无法保证。 这种暂停线程的现象叫"stop the world",它给用户带去了不良体验,但无法完全避免。 1.对象存活判定 首先,需要知道哪些对象还在存活以及哪些对象可以回收,判定方法主要有引用

任何对象都有它的生命周期,所以jvm需要定时地回收掉不用的内存,防止内存耗完。GC的时候必须暂停所有的java线程,不可以出现在分析过程中对象引用关系还在不停变化的情况。否则分析结果的准确性无法保证。
这种暂停线程的现象叫"stop the world",它给用户带去了不良体验,但无法完全避免。

1.对象存活判定

首先,需要知道哪些对象还在存活以及哪些对象可以回收,判定方法主要有引用计数法以及引用链法两种,jvm使用的是后者 引用链法

1.1引用计数法

为每个对象维护一个引用计数器,每当有一个地方引用它时,此计数器+1,当引用失效时,计数器-1.当计数器变为0时就说明此对象可以被回收。
计数器+1的情况有:赋值给一个引用,放入一个容器等。
计数器-1的情况有:原引用指向其他的对象。
引用计数法并没有被用在java虚拟机中,因为它不能解决对象间循环引用问题。如:
class MyClass{
public Object obj;
}
main(){
MyClass a=new MyClass();
MyClass b=new MyClass();
a.obj=b;
b.obj=a;
b=a=null;//此时a与b对象都不能再次被访问,但它们的引用计数并不为0.
}

1.2引用链法

维护一批"gc roots"作为一批树的根,new出来的java对象作为节点。父子节点间的关系即为引用关系,当一个节点与根相连通时,对象不被回收;当二者不连通时,对象会被回收。它解决了对象间的循环引用问题。

一般选取各个线程中的线程栈中的对象作GCRoots。

2.finalize()方法

Object基类方法,用于定义垃圾收集器在回收对象所占内存之前所做的清理工作。它的设计目的就是回收特殊渠道申请的内存,比如本地代码申请的内存。

3.老年代垃圾收集器

3.1 CMS收集器

CMS,Concurrent Mark Sweep。
特点:追求停顿时间最短。它是 老年代收集器。
服务端的java程序重视响应速度,希望系统停顿时间最短,以给用户带来良好的体验。
CMS收集器是基于“标记-清除”算法实现的,分为四个步骤——初始标记,并发标记,重新标记,并发清除。
阶段 简述 时长 停止工作线程
初始标记 标记 GCRoots能直接关联到的对象 Y
并发标记 进行GC Roots tracing的过程 N
重新标记 修正并发标记期间产生变动的标记 Y
并发清除 执行内存回收 N

CMS的回收线程数x=(cpu数量+3)/4。

3.1.1 vm参数

由于在并发清除阶段,垃圾回收线程与用户线程并发执行,所以不能像其他收集器那样等到老年代几乎被占满了再进行收集,而是需要预留一部分供GC线程自身使用。所以会有一个比例阀值x(如0.9),老年代已经用掉的空间超过x时进行CMS回收。这个阀值x可以通过“ -XX:CMSInitiatingOccupancyFraction”参数来调整。适当调高此参数可以降低内存回收次数从而获取更好的性能。
如果CMS回收期间内存不够用,就会出现一次“Concurent Mode Failure”失败。虚拟机就会临时启用Serial Old收集器来重新进行老年代的收集。

3.2 Parallel Old

Parallel Old是Parallel Scavenge的老年代版本。

3.3 Serial Old

Serial Old是Serial收集器的老年代版本。

4.年轻代收集器

年轻代也成为新生代。新生代GC也是需要 stop the world的,通常为 几十毫秒
每当eden区满,就触发一次yong GC。

4.1 Serial

Serial是最基本、历史悠久的年轻代收集器。它在GC时必须暂停所有工作线程,所以现在一般不用了。

4.2 ParNew

ParNew其实就是Serial的多线程版本。现在一般也不用。

4.3 Parallel Scavenge

Parallel Scavenge的目标是达到一个可控制的吞吐量。吞吐量=工作线程运行时间 / (工作线程运行时间+垃圾收集时间).。虚拟机总共运行了100分钟,其中垃圾收集花费1分钟,那么吞吐量就是99%。


5.gc日志打印

JVM提供了大量命令行参数,打印信息,供调试使用。主要有以下一些:

  • -XX:+PrintGC
    输出形式:[GC 118250K->113543K(130112K), 0.0094143 secs]

                    [Full GC 121376K->10414K(130112K), 0.0650971 secs]

  • -XX:+PrintGCDetails
    输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]

                    [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]

  • -XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可与上面两个混合使用
    输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
  • -XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,程序未中断的执行时间。可与上面混合使用
    输出形式:Application time: 0.5291524 seconds
  • -XX:+PrintGCApplicationStoppedTime:打印垃圾回收期间程序暂停的时间。可与上面混合使用
    输出形式:Total time for which application threads were stopped: 0.0468229 seconds
  • -XX:PrintHeapAtGC:打印GC前后的详细堆栈信息
    输出形式:
    34.702: [GC {Heap before gc invocations=7:
     def new generation   total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000)
    eden space 49152K,  99% used [0x1ebd0000, 0x21bce430, 0x21bd0000)
    from space 6144K,  55% used [0x221d0000, 0x22527e10, 0x227d0000)
      to   space 6144K,   0% used [0x21bd0000, 0x21bd0000, 0x221d0000)
     tenured generation   total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000)
    the space 69632K,   3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000)
     compacting perm gen  total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
       the space 8192K,  35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
        ro space 8192K,  66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
        rw space 12288K,  46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
    34.735: [DefNew: 52568K->3433K(55296K), 0.0072126 secs] 55264K->6615K(124928K)Heap after gc invocations=8:
     def new generation   total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000)
    eden space 49152K,   0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000)
      from space 6144K,  55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000)
      to   space 6144K,   0% used [0x221d0000, 0x221d0000, 0x227d0000)
     tenured generation   total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000)
    the space 69632K,   4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000)
     compacting perm gen  total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
       the space 8192K,  35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
        ro space 8192K,  66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
        rw space 12288K,  46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
    }
    , 0.0757599 secs]
  • -Xloggc:filename:与上面几个配合使用,把相关日志信息记录到文件以便分析。

目录
相关文章
|
24天前
|
算法 Java
JVM垃圾回收机制
JVM垃圾回收机制
15 0
|
1月前
|
Java 程序员
探讨JVM垃圾回收机制与内存泄漏
探讨JVM垃圾回收机制与内存泄漏
|
2月前
|
算法 Java 关系型数据库
掌握这3个技巧,你也可以秒懂JAVA性能调优和jvm垃圾回收
JVM 是一个虚拟化的操作系统,类似于 Linux 和 Window,只是他被架构在了操作系统上进行接收 class 文件并把 class 翻译成系统识别的机器码进行执行,即 JVM 为我们屏蔽了不同操作系统在底层硬件和操作指令的不同。
24 0
|
2月前
|
存储 缓存 算法
JVM的垃圾回收机制
JVM的垃圾回收机制
|
3月前
|
算法 Java
JVM GC和常见垃圾回收算法
JVM GC和常见垃圾回收算法
48 0
|
3月前
|
存储 算法 Java
理解JVM的内存模型和垃圾回收算法
理解JVM的内存模型和垃圾回收算法
43 2
|
3月前
|
算法 Java
jvm性能调优 - 15JVM的老年代垃圾回收器CMS的缺点
jvm性能调优 - 15JVM的老年代垃圾回收器CMS的缺点
56 0
|
14天前
|
存储 前端开发 安全
JVM内部世界(内存划分,类加载,垃圾回收)(上)
JVM内部世界(内存划分,类加载,垃圾回收)
48 0
|
18天前
|
存储 缓存 算法
深度解析JVM世界:垃圾判断和垃圾回收算法
深度解析JVM世界:垃圾判断和垃圾回收算法
|
1月前
|
Java Serverless 对象存储
Serverless 应用引擎常见问题之jvm在进行垃圾回收的时候会导致重启如何解决
Serverless 应用引擎(Serverless Application Engine, SAE)是一种完全托管的应用平台,它允许开发者无需管理服务器即可构建和部署应用。以下是Serverless 应用引擎使用过程中的一些常见问题及其答案的汇总:
22 0