JVM 学习路线图

在这里插入图片描述

堆的核心概念

在这里插入图片描述
在这里插入图片描述
JVM 参数 -Xms10m -Xmx10m
下面的容量相加为10M
VisualVM 工具
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

内存细分

在这里插入图片描述
在这里插入图片描述

堆空间大小的设置

在这里插入图片描述

/**
 * 1. 设置堆空间大小的参数
 * -Xms 用来设置堆空间(年轻代+老年代)的初始内存大小
 *      -X 是jvm的运行参数
 *      ms 是memory start
 * -Xmx 用来设置堆空间(年轻代+老年代)的最大内存大小
 *
 * 2. 默认堆空间的大小
 *    初始内存大小:物理电脑内存大小 / 64
 *    最大内存大小:物理电脑内存大小 / 4
 *
 * 3. 手动设置:-Xms600m -Xmx600m
 *     开发中建议将初始堆内存和最大的堆内存设置成相同的值。
 *
 * 4. 查看设置的参数:方式一: jps -l   /  jstat -gc 进程id
 *                 方式二:-XX:+PrintGCDetails
 *
 * @author shkstart  shkstart@126.com
 * @create 2020  20:15
 */
public class HeapSpaceInitial {
    public static void main(String[] args) {

        //返回Java虚拟机中的堆内存总量
        long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
        //返回Java虚拟机试图使用的最大堆内存量
        long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;

        System.out.println("-Xms : " + initialMemory + "M");
        System.out.println("-Xmx : " + maxMemory + "M");

        System.out.println("系统内存大小为:" + initialMemory * 64.0 / 1024 + "G");
        System.out.println("系统内存大小为:" + maxMemory * 4.0 / 1024 + "G");
    }
}

java visualVM 观察OOM
/**
 * -Xms600m -Xmx600m
 * @author shkstart  shkstart@126.com
 * @create 2020  17:51
 */
public class HeapInstanceTest {
    byte[] buffer = new byte[new Random().nextInt(1024 * 200)];

    public static void main(String[] args) {
        ArrayList<HeapInstanceTest> list = new ArrayList<HeapInstanceTest>();
        while (true) {
            list.add(new HeapInstanceTest());
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

VisualVM 工具查看堆内存变化
在这里插入图片描述

观察YGC和堆区内存占用情况,当 Old 区满时,Eden区再次满时,程序就会报错:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

JProfiler 11 工具查看堆内存情况
在这里插入图片描述

年轻代与老年代

在这里插入图片描述
在这里插入图片描述

jps -l 查询进程pid
jstat -gc pid 查看堆空间占用情况 (单位为字节,除以1024转为兆)

在这里插入图片描述
C : 代表总大小
U : 代表已使用大小

jinfo -flag NewRatio pid 查看 pid 的jvm参数 NewRatio 的值

在这里插入图片描述

默认情况下,新生代和老年代的比例为 1:2
例如:-Xmx=600M 则 新生代:200M ,老年代:400M,而新生代的分配比率为 8:1:1,则 S0:20M S1:20,Eden:160M
比率为8:1:1 需要配置参数为: -XX:SurvivorRatio=8

在这里插入图片描述

/**
 * -Xms600m -Xmx600m
 * <p>
 * -XX:NewRatio : 设置新生代与老年代的比例。默认值是2.
 * <p>
 * -XX:SurvivorRatio :设置新生代中Eden区与Survivor区的比例 8:1:1。默认值是8
 * -XX:-UseAdaptiveSizePolicy :关闭自适应的内存分配策略  (暂时用不到)
 * <p>
 * -Xmn:设置新生代的空间的大小。 (一般不设置)
 *
 * @author shkstart  shkstart@126.com
 * @create 2020  17:23
 */
public class EdenSurvivorTest {
    public static void main(String[] args) {
        System.out.println("我只是来打个酱油~");
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

图解对象分配过程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

当Eden区满时,则触发 YGC,而S0或S1 满时则不会触发 YGC

在这里插入图片描述
在这里插入图片描述

常用调优工具

在这里插入图片描述

MinorGc和MajorGc和FullGc

在这里插入图片描述

调优的重点就时减少GC的次数

分代式GC触发条件

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/**
 * 测试MinorGC 、 MajorGC、FullGC
 * -Xms9m -Xmx9m -XX:+PrintGCDetails
 * 
 * @author shkstart  shkstart@126.com
 * @create 2020  14:19
 */
public class GCTest {
    public static void main(String[] args) {
        int i = 0;
        try {
            List<String> list = new ArrayList<>();
            String a = "atguigu.com";
            while (true) {
                list.add(a);
                a = a + a;
                i++;
            }

        } catch (Throwable t) {
            t.printStackTrace();
            System.out.println("遍历次数为:" + i);
        }
    }
}

产生GC日志和堆空间大小日志:-XX:+PrintGCDetails

在这里插入图片描述

堆分区分代思想

在这里插入图片描述
在这里插入图片描述

内存分配策略

在这里插入图片描述
在这里插入图片描述

空间分配担保:因为Survior区比较小,把Survior 区无法存放的对象,直接存放到老年代区,前提是老年代区可以容纳下该对象

/** 测试:大对象直接进入老年代
 * -Xms60m -Xmx60m -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:+PrintGCDetails
 * @author shkstart  shkstart@126.com
 * @create 2020  21:48
 */
public class YoungOldAreaTest {
    public static void main(String[] args) {
        byte[] buffer = new byte[1024 * 1024 * 20];//20m

    }
}

Eden:16M ,S1:2M , S2:2M , Old:40M
没有打印GC日志,说明没有发生GC,对象直接进入老年代

在这里插入图片描述

对象分配过程:TLAB

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/**
 * 测试-XX:UseTLAB参数是否开启的情况:默认情况是开启的
 *
 * @author shkstart  shkstart@126.com
 * @create 2020  16:16
 */
public class TLABArgsTest {
    public static void main(String[] args) {
        System.out.println("我只是来打个酱油~");
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

查看jvm 默认参数

在这里插入图片描述

堆空间常用的jvm参数

/**
 * 测试堆空间常用的jvm参数:
 * -XX:+PrintFlagsInitial : 查看所有的参数的默认初始值
 * -XX:+PrintFlagsFinal   :查看所有的参数的最终值(可能会存在修改,不再是初始值)
 * 		-XX:+PrintFlagsFinal -XX:SurvivorRatio=5  //修改jvm参数
 *      具体查看某个参数的指令: jps:查看当前运行中的进程
 *                             jinfo -flag SurvivorRatio 进程id
 *
 * -Xms:初始堆空间内存 (默认为物理内存的1/64)
 * -Xmx:最大堆空间内存(默认为物理内存的1/4)
 * -Xmn:设置新生代的大小。(初始值及最大值)
 * -XX:NewRatio:配置新生代与老年代在堆结构的占比
 * -XX:SurvivorRatio:设置新生代中Eden和S0/S1空间的比例
 * -XX:MaxTenuringThreshold:设置新生代垃圾的最大年龄
 * -XX:+PrintGCDetails:输出详细的GC处理日志
 * 打印gc简要信息:① -XX:+PrintGC   ② -verbose:gc
 *     -XX:HandlePromotionFailure:是否设置空间分配担保
 *
 * @author shkstart  shkstart@126.com
 * @create 2020  17:18
 */
public class HeapArgsTest {
    public static void main(String[] args) {

    }
}

在这里插入图片描述

:= 5 :说明jvm参数值修改了

在这里插入图片描述

逃逸分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/**
 * 逃逸分析
 *
 *  如何快速的判断是否发生了逃逸分析,大家就看new的对象实体是否有可能在方法外被调用。
 * @author shkstart
 * @create 2020 下午 4:00
 */
public class EscapeAnalysis {

    public EscapeAnalysis obj;

    /*
    方法返回EscapeAnalysis对象,发生逃逸
     */
    public EscapeAnalysis getInstance(){
        return obj == null? new EscapeAnalysis() : obj;
    }
    /*
    为成员属性赋值,发生逃逸
     */
    public void setObj(){
        this.obj = new EscapeAnalysis();
    }
    //思考:如果当前的obj引用声明为static的?仍然会发生逃逸。

    /*
    对象的作用域仅在当前方法中有效,没有发生逃逸
     */
    public void useEscapeAnalysis(){
        EscapeAnalysis e = new EscapeAnalysis();
    }
    /*
    引用成员变量的值,发生逃逸
     */
    public void useEscapeAnalysis1(){
        EscapeAnalysis e = getInstance();
        //getInstance().xxx()同样会发生逃逸
    }
}

在这里插入图片描述

注意:开发时能使用局部变量的,就不要使用在方法外定义

在这里插入图片描述

/**
 * 栈上分配测试
 * <p>
 * 测试1
 * 未开启逃逸分析: -Xmx1G -Xms1G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails
 * 开启逃逸分析: -Xmx1G -Xms1G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails
 * <p>
 * 都没有产生gc日志,只是开启逃逸分析时,执行的比较快
 * <p>
 * 测试2
 * 未开启逃逸分析: -Xmx256m -Xms256m -XX:-DoEscapeAnalysis -XX:+PrintGCDetails
 * 产生了gc日志
 * <p>
 * 开启逃逸分析: -Xmx256m -Xms256m -XX:+DoEscapeAnalysis -XX:+PrintGCDetails
 * 没有产生gc日志
 *
 * @author shkstart  shkstart@126.com
 * @create 2020  10:31
 */
public class StackAllocation {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        for (int i = 0; i < 10000000; i++) {
            alloc();
        }
        // 查看执行时间
        long end = System.currentTimeMillis();
        System.out.println("花费的时间为: " + (end - start) + " ms");
        // 为了方便查看堆内存中对象个数,线程sleep
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
    }

    private static void alloc() {
        User user = new User();//未发生逃逸
    }

    static class User {

    }
}

未开启逃逸分析:执行结果:花费的时间为: 106 ms
内存中维护很多user 对象

在这里插入图片描述

开启逃逸分析:执行结果:花费的时间为: 7 ms
内存中没有维护很多user 对象
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
标量替换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/**
 * 标量替换测试
 * 未开启标量替换: -Xmx100m -Xms100m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-EliminateAllocations
 * <p>
 * 开启标量替换 : -Xmx100m -Xms100m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:+EliminateAllocations
 * 结论:开启标量替换时,花费的时间更少,没有产生gc
 *
 * @author shkstart  shkstart@126.com
 * @create 2020  12:01
 */
public class ScalarReplace {
    public static class User {
        public int id;
        public String name;
    }

    public static void alloc() {
        User u = new User();//未发生逃逸
        u.id = 5;
        u.name = "www.atguigu.com";
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            alloc();
        }
        long end = System.currentTimeMillis();
        System.out.println("花费的时间为: " + (end - start) + " ms");
    }
}

在这里插入图片描述
jdk 64 位默认就是sever 模式
在这里插入图片描述

总结

在这里插入图片描述

参考文档

Java SE 8 Documentation
java8 JVM参数文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值