zoukankan      html  css  js  c++  java
  • jvm-gc

    gc简述

    gc分为minor gc和full gc,区别在于前者指回收新生代(1个Eden和2个Survivor),后者通常会先进行一次minor gc然后再full gc,full gc回收老年代(Tenure),顺带回收永久代(Perm,jdk8中被Metadata取代,Metadata位于native memory,有独立的gc机制)。

    minor gc通常采用标记-复制算法,这种算法需要先对活跃对象进行标记,然后将所有被标记对象复制到另一个完全空旷的空间,算法缺点很明显,需要额外的空旷空间,优点是空间中不会出现碎片,这种算法适合回收存有大量朝生夕灭的对象的空间,新生代就是这样的空间。

    full gc通常采用标记-清除(可以通过设置决定是否压缩),这种算法首先标记活跃对象,然后回收未被标记的对象的空间,算法缺点是容易出现空间碎片,优点是不需要重置对象引用地址,这种算法适合存放大对象、老对象的空间使用,老年代就是这样的空间。

    cms(与cms搭配的新生代收集器默认为ParNew,是一款多线程收集器)在进行full gc时,是并发执行的,为了避免在gc期间有对象进入老年代,cms不能在老年代满时才gc,而应当空出一些空间,但这样仍然不能保证空出的空间足够容纳对象,所以就会出现“Concurrent Mode Failure”,这时jvm就会启动Seiral Old(一种串行收集器)进行gc(如果空间仍然不足,就OOM)。

    jvm参数设置

    经过测试发现 jvm的默认设置中,Eden:Survivor1:Survivor2=8:1:1,Young Gen:Tenure Gen=1:2,新对象变成老对象需要经历15次minor gc,新创建的对象会优先存放在Eden中,如果Eden空间不足才会尝试放入Tenure中(如果Tenure也放不下,就full gc)。但这些都是可以设置的:

    -Xms512M,设置初始heap大小,默认是物理内存的1/64,

    -Xmx512M,设置最大heap大小,默认是物理内存的1/4,

    -Xmn256M,设置新生代大小(Eden+2个Survivor),这里比较有意思的是虽然设置了-Xmn256M,但新生代真正可被利用了一定小于256M(Eden+1个Survivor),因为会有一个Survivor永远空旷,这点在gc log中就有体现,比如[ParNew: 13621K->2773K(118016K),118016K=115.25M,而我设置了-Xmn128M(115.25/128=0.9,正好符合Eden和Survivor的默认比例)。

    -XX:SurvivorRatio=n,设置Survivor1:Survivor2:Eden=1:1:n,

    -XX:NewRatio=n,设置Young Gen:Tenure Gen=1:n,

    -MaxTenuringThreshold=15,年龄大于15的对象(经历过15次minor gc)进入老年代,

    -PretenureSizeThreshold=1M,大于1M的对象直接进入老年代,

    -XX:+UseConcMarkSweepGC,显示声明使用CMS进行full gc,

    -XX:+UseCMSCompactAtFullCollection,在cms进行full gc后压缩空间,默认是开启的,

    -XX:CMSFullGCsBeforeCompaction=n,CMS执行n次无压缩full gc后,进行一次带压缩的full gc,

    -Xss2m,设置线程栈大小为1m,java中一个线程的空间大小是有限制的(线程空间并不是指Thread对象所占的空间,而是栈空间)。JDK5.0以后这个值是1M。与这个线程相关的数据将会保存在其中。但是当线程空间满了以后,将会出现Fatal: Stack size too small异常(java.lang.StackOverflowError就和该大小相关)。

     -XX:+PrintGCDetails,打印详细gc log,

     -XX:+PrintGC或-verbose:gc,打印简单gc log,

     gc root

    gc从gc roots开始可达性遍历,进行标记-清除: 

    来看gc root有哪些:

    • Class - class很难被回收,因为回收条件苛刻,1加载该class的ClassLoader已经被回收,2该class的所有实例已经被回收,3该class没有被引用(其实前两条也可以归结为第三条,第一条是因为ClassLoader会将加载过的class存放在vector中,第二条是因为每个实例都会持有一个其类class对象的引用)。jvm有3个ClassLoader(Bootstrap、ext、sys),这3个ClassLoader在整个jvm运行期间都是存在的,所以由这三个loader加载的class在整个jvm运行期都不会被回收(不满足第一条),如果是自定义的ClassLoader,class(满足回收条件)就会被回收了。
    • Thread - 活着的线程(对象)
    • Stack Local - 局部变量(包括方法形参),这里最容易产生朝生夕灭的对象
    • JNI Local - jni方法的局部变量(包括方法形参)
    • JNI Global - 全局jni引用
    • Monitor Used - 被synchronized用作monitor的对象
    • Held by JVM - objects held from garbage collection by JVM for its purposes.

    参考:https://plumbr.eu/blog/garbage-collection/minor-gc-vs-major-gc-vs-full-gc

      https://www.dynatrace.com/resources/ebooks/javabook/how-garbage-collection-works/

  • 相关阅读:
    PHP设计模式
    秒杀方案
    lua 安装
    docker 相关命令
    dockerfile
    JS工具对象 DATE 方法
    JS工具对象 Array
    JS工具对象 String 10种常用 方法
    工具对象
    JS工具对象Math 7个常用 方法
  • 原文地址:https://www.cnblogs.com/holoyong/p/7253144.html
Copyright © 2011-2022 走看看