GC

作者: CoderZzbJohn | 来源:发表于2019-06-16 21:08 被阅读0次

    1.年轻代 Eden,S0,S1 。对象到一定年龄(minor gc次数)晋升到老年代
    2.老年代
    3.永久代,方法区,MetaSpace。存放类相关信息,静态变量,常量等。

    触发FullGC:
    1.老年代在一次major GC之后,内存还是不够,无法放入大对象或大数组,或者内存碎片过多。
    2.担保失败,年轻代进入老年代之前,会统计平均每次晋升空间,如果平均晋升空间超过了老年代剩余空间,则触发fullGC。
    3.metaspace溢出。空间不足,或者随便太多无法继续加载类对象。

    promotion failed – concurrent mode failure
    Minor GC后, Survivor空间容纳不了剩余对象,将要放入老年代,老年代有碎片或者不能容纳这些对象,就产生了concurrent mode failure, 然后进行stop-the-world的Serial Old收集器。
    解决办法:-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5 或者调大新生代或者Survivor空间

    concurrent mode failure
    CMS是和业务线程并发运行的,在执行CMS的过程中有业务对象需要在老年代直接分配,例如大对象,但是老年代没有足够的空间来分配,所以导致concurrent mode failure, 然后需要进行stop-the-world的Serial Old收集器。

    解决办法:+XX:CMSInitiatingOccupancyFraction,调大老年带的空间,+XX:CMSMaxAbortablePrecleanTime

    总结一句话:使用标记整理清除碎片和提早进行CMS操作。

    MetaSpace out of memory 导致fullGC排查:

    1.Aviator包,google表达式计算引擎,AviatorEvaluator.execute或者AviatorEvaluator.complie方法通过asm生成对应的Expression计算类,导致metaSpace中加载的类过多,MetaSpace溢出。解决方案是加缓存,AviatorEvalutor.execute("",cache:true) 当遇到相同的表达式时,不会重新生成类。
    2.-verbose:class jvm启动参数。设置该参数可查看对应的加载的类
    3.-Dsun.reflect.inflationThreshold=2147483647 当调用反射方法过多时,jvm会进行优化,生成代理类来代替反射。指定该参数,禁止生成代理类,一直调用反射方法,防止加载过多的类。
    4.-XX:MetaspaceSize :该参数代表的不是Metaspace初始化的内存大小。而是当Metaspace大小接近该值时,会进行FullGC。jvm会根据另外两个最高最低使用率来动态调整MetaspaceSize大小。
    -XX:MaxMetaspaceSize 超过该值时会报oom。
    5.反射原理:默认使用jni方式,通过调用native方法来调用。当调用次数超过15次时,生成GeneratorMethodAccessor实现具体的方法代理,然后通过sun.reflect.DelagatingClassLoader类加载器来加载代理类。Method中缓存着相关的数据,都是弱引用(class对象中包含了method相关的信息,weakReference类型),当内存空间剩余较低时容易被回收,因此会重新创建类加载器来加载反射方法的代理类,这样容易造成metaspace中有多个类加载器,正常web项目几十个类加载器,但是resume-service排查时有两千多个类加载器。另外一点,类加载器在metaspace中是单独分配内存的,占用较大空间,无论该加载器是加载一个类还是多个类都会单独分配内存,所以造成很大的空间碎片,因此gc日志上看的,used140m,但是commited的内存达到了256m。
    6.JVM内部为了实现高效分配,在类加载器第一次加载类的时候,会在Metaspace分配一个独立的内存块,随后该类加载加载的类信息都保存在该内存块。但如果这个类加载器只加载了一个类或者少数类,那这块内存就被浪费了,如果类加载器又特别多,那内存碎片就产生了。

    // 1.2 获取到Java进程的pid,下述指令为sankuai用户名后的数字,或者使用top指令查看Java的pid也可
    ps -ef|grep java

    // 1.3 dump出内存快照,pid为1.2中查得的pid
    jmap -dump:format=b,file=/xx/xx/xx.hprof pid

    .MetaSpace中对象被回收的条件:

    1、该类所有的实例都已经被回收;
    2、加载该类的ClassLoader已经被回收;
    3、该类对应的java.lang.Class对象没有任何地方被引用。

    GC:

    GCRoot

    1.局部方法中的对象。
    2.已经加载的类的static中的对象。
    3.方法区中常量应用的对象
    spring容器中的对象属于哪一类???

    模式

    1.串行or并行:单线程或者多线程回收垃圾。
    2.并发or Stop-the-world:回收过程中是否需要停止应用。Stop-the-world过程中堆大小不再发生变化。

    垃圾收集器

    1.串行收集器:

    1.年轻代:Eden,S0,S1。将Eden和S0中的存活对象移到S1中,如果S1内存不够,剩余对象直接进入老年代。在每一次minorGC之前都会进行一次判断。基于统计,计算出每次年轻代晋升到老年代的平均大小,if (老年代剩余空间 < 平均大小) 触发 full gc。
    2.老年代: 标记->清除->压缩

    2.并行垃圾收集器:

    1.年轻代:多线程STW+复制。
    2.老年代:标记->清除 ->压缩。 单线程。与串行收集器相同。

    3.并行压缩收集器

    1.年轻代:多线程STW+复制。
    2.老年代:多线程 标记->清除->压缩。

    CMS

    1.年轻代:多线程STW+复制
    2.老年代:initial mark (初始标记,STW,确定GC root)+ current mark(并发标记) + remark(STW,再标记) + concurrent sweep(并发清理),不压缩。
    由于在并发清理过程中,可能会新产生一些垃圾(浮动垃圾)导致老年代空间不足,concurrent mode failure,可以通过设置XX:CMSInitiatiingOccupancyFranction。提前让老年代gc,jdk7默认值68,jdk8之后调整成了92.

    相关文章

      网友评论

          本文标题:GC

          本文链接:https://www.haomeiwen.com/subject/fmbgfctx.html