JVM垃圾收集器

2020-03-01  本文已影响0人  Teemo_fca4
七大垃圾收集器

GC算法(可达性分析,复制,标清,标整)是内存回收的方法论,垃圾收集器就是这些方法论的落地实现: 简称 4大算法,7大垃圾收集器

四类垃圾收集器
image.png

JVM对参数的缩写:
DefNew 等价于 Default New Generation
Tenured 等价于 Old
ParNew 等价于 Parallel New Generation
PSYoungGen 等价于Parallel Scavenge
ParOldGen 等价于 Parallel Old Generation
Server/Client 模式:
只需要掌握Server模式即可,Client模式基本不会用
32位Windows操作系统,不管什么配置都使用Client模式,
32位其他系统,2G内存同时有2个以上cpu使用Server模式,否则使用Client模式
64位操作系统,使用Server模式

具体的收集器

image.png
新生代的GC收集器包含以下三个
//收集器公用代码
public class Test {
    public static void main(String[] args) throws Exception{
        String str = "aaaaa";
        byte[] arr = new byte[20*1024*1024];
    }
}
image.png
串行收集器是最老最稳定效率最高的的收集器,因为会产生较长的停顿,所以现在基本不用。
-Xms8m -Xmx8m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseSerialGC
上面的参数配置后,JVM会(默认)使用的DefNew+Tenured组合,新生代,老年代都使用串行垃圾器
image.png
老年代的GC收集器包含以下三个

CMS收集垃圾:分为四个过程
1 初始标记(initial mark):暂停用户线程
只是标记一下GC Roots能直接关联的对象,速度很快,但是仍然需要暂停所有线程
2 并发标记(concurrent mark)和用户线程一起工作
进行GC Roots Tracing 跟踪过程,和用户线程一起工作,不需要暂停工作线程,主要标记过程,标记全部对象
3重新标记(remark):暂停用户线程
为了修正并发标记期间,因用户线程继续运行而导致标记产生变动的那一部分对象的标记记录,因此需要做一次修正,仍然需要暂停所有线程
4 并发清除(concurrent sweep):和用户线程一起工作
清除GC Roots不可达对象,和用户线程一起工作,不需要暂停用户线程,基于标记结果,直接清理对象
四步过程中,由于耗时最长的并发标记和并发清除过程是并发的,没有暂停用户线程,所以总体的来看,CMS收集器的内存回收是和用户线程一起并发工作执行的
说明:由于并发进行,CMS在收集与应用线程会同时增加对堆内存的占用,也就是说,CMS必须要在老年代堆内存用尽之前完成垃圾回收,否则CMS回收失败时,将触发担保机制--使用串行老年代收集器以STW的方式进行一次性GC,从而造成较大的停顿时间。
CMS的优点:并发收集:停顿低
CMS的缺点 :1 并发执行,对cpu资源压力大,2 采用标记-清除算法会导致大量碎片

GC垃圾器组合的选择

G1收集器

上面的六种收集器的特点是:
1 新生代和老年代是各自独立且连续的内存卡
2 新生代收集使用单eden+S0+S1进行复制算法
3 老年代收集必须扫描整个老年代区域
从这几个方面来说,G1完全是全新的收集器。G1收集器的设计目标是取代CMS收集器,在保留CMS收集器的优点下,还有以下改进。
1 G1收集器使用标-整算法(局部使用复制算法),仍然属于分代收集器,不会产生内存碎片。
2 G1的停顿更加可控,G1收集器在停顿时间有预测机制,用户可以指定期望停顿时间。
内存方面来说G1收集器的Eden,Survivor,Tenured内存区域不再是连续的了,而是变成了一个个大小一样的region,每个region从1M到32M不等(JVM在启动的时候会设置这些区域的大小,最多设置2048个区域,所以最大能支持的内存是32M*2048=64G),一个region可能是Eden,Survivor或者Tenured,一个region在A时刻可能是Eden,在B时刻可能是Survivor或者Tenured 其身份是不确定的。

image.png

region中新生代,新生代垃圾回收依然暂停所有用户线程,将存活的对象复制到老年代或者Survivor空间中,整理
region中老年代,G1收集器将对象从一个区域复制到另外一个区域 然后整理,完成清理工作,所以 正常的处理过程中 G1完成了堆压缩,这样就不会有碎片的问题了。
G1收集器中还有一个特殊的区域Humongous区域,用于专门存放巨大对象的,如果一个H区存放不下这个巨大对象,那么G1收集器会寻找连续的H分区来存储这个对象,为了找出连续的H区,G1不得不启动Full GC。\

G1运行示意图 初始标记的速度很快很快

image.png

配置参数
-Xms8m -Xmx8m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseG1GC


image.png
内存分配规则

Linux命令查看系统情况

**Cpu占用过高,如何分析原因? **


import java.util.Random;
//问题代码例子
public class Test {
    public static void main(String[] args) throws Exception{
        while (true){
            System.out.println(new Random().nextInt(100000000));
        }
    }
}

1 使用top找出cpu占比最高的进程

image.png
2 使用ps -ef | grep java 或者jps -l 看看到底是什么样的程序给我们惹麻烦
image.png
image.png
3 ps -mp 6091 -o THREAD,tid,time 找到6091 这个进程对应的所有线程
image.png
4 将上面的线程号转为16进制(小写)的线程号 6092 --> 17cc
5 使用jstack 查看线程堆栈信息
jstack 6091 | grep 17cc -A100 (这里是看一百行)
image.png
这里的最终结果是我们的Test.java的第七行代码出现了问题
上一篇 下一篇

猜你喜欢

热点阅读