Java基础_虚拟机4:(JVM调优)

目录

1:首先我们需要知道JVM的参数设置

1.1:jvm信息输出

1.2:验证jvm默认值

2:Jvm内存设置

2.1:堆内存设置(默认年轻代:老年代=1:2)

2.2:堆内存设置(自定义年轻代和老年代)

2.3:设置新生代的伊甸、to、from大小

3:栈内存设置默认是1M,-Xss2m设置

4:元空间大小设置默认21M,自动扩展

5:其它JVM参数

6:JVM调优

6.1:visualvm调优

6.2:实时监控内存溢出OOM

6.3:日志监控内存溢出OOM案例

6.4:CPU占用高的时候

6.5:服务器cpu占用高 

6.6:visualvm连接服务器


1:首先我们需要知道JVM的参数设置

1.1:jvm信息输出

public class JvmTest1 {
    /**
     * 虚拟机参数设置
     *
     *  -XX:+PrintGCDetails   输出虚拟机的堆、栈、元空间等信息
     */
    public static void main(String[] args) {

    }
}

结果截图:

结果分析:

PSYoungGen(年轻代):total 76288K ,Parallel Scavenge 并行垃圾回收器

                 eden space 65536K  伊甸区

                 from space 10752K,   from区

                  to   space 10752K,    to区

ParOldGen(老年代):total 175104K,Parallel Old 并行垃圾回收器

        年轻代+老年代=76288K+175105K=251392K=245.5MB  约等于作者本机16GB的1/64

        堆默认情况下,初始堆内存大小为:电脑内存大小/64,但是不绝对,根据内存动态来的

        堆默认情况下,最大堆内存大小为:电脑内存大小/4,但是不绝对,根据内存动态来的

Metaspace(元空间) :  初始值根据系统来设置,默认没有上限

1.2:验证jvm默认值

代码如下:

public class JvmTest2 {
    public static void main(String[] args) {
        //返回Java虚拟机中的内存总量。
        Long totalMemory = Runtime.getRuntime().totalMemory();
        System.out.println("TOTAL_ MEMORY = "+totalMemory +"(字节)"+(totalMemory/1024/1024) + "MB");

        //返回Java虚拟机试图使用的最大内存量。
        long maxMemory = Runtime.getRuntime().maxMemory();
        System.out.println("MAX_MEMORY ="+maxMemory +"(字节)、"+(maxMemory/1024/1024) + "MB");

    }
}

输出结果如下:

2:Jvm内存设置

2.1:堆内存设置(默认年轻代:老年代=1:2)

public class JvmHeadTest1 {
    /**
     * jvm的堆内存设置
     * -Xms10m  初始堆容量大小
     * -Xmx10m  堆容量最大值
     * -XX:+PrintGCDetails
     * 
     * -Xms10m -Xmx10m  -XX:+PrintGCDetails
     */
    public static void main(String[] args) {

    }
}

截图:

堆内存重点分析:

我们设置的堆的最大和初始容量都是10M

年轻代=2048+512+512=3M

老年代=7168K=7M

年轻代+老年代=2048+512+512+7168=10240K=10m

年轻代:老年代=3:7 约等于1:2(10M不能满足默认的的1:2,设置9M的时候可以看到)

年轻代的伊甸、from、to分别是2048、512、521。比例是4:1:1

总结:年轻代小,老年代大,默认是1:2

2.2:堆内存设置(自定义年轻代和老年代)

有两种方法

1:-Xmn 直接设置年轻代的大小,总共容量默认10m,设置新生代4m

public class JvmHeadTest1 {
    /**
     * jvm的堆内存设置
     * -Xms10m  初始堆容量大小
     * -Xmx10m  堆容量最大值
     * -Xmn4m   直接设置新生代大小(优先级高于比例设置)
     * -XX:NewRatio=4 新生代:老年代=1:4 默认值是2也就是1:2
     * -XX:+PrintGCDetails
     *
     * 1:-Xms10m -Xmx10m -XX:NewRatio=4   -XX:+PrintGCDetails (NewRatio设置新生代、老年代比例)
     *
     * 2:-Xms10m -Xmx10m -Xmn4m -XX:NewRatio=4   -XX:+PrintGCDetails (Xmn4m直接设置新生代大小,优先级高于比例设置)
     */
    public static void main(String[] args) {

    }
}

截图分析:

2:-XX:NewRatio=4 设置年轻代和老年代的比值,默认是1:2,总共容量默认10m,这里设置1:4

设置新的比例

public class JvmHeadTest1 {
    /**
     * jvm的堆内存设置
     * -Xms10m  初始堆容量大小
     * -Xmx10m  堆容量最大值
     * -XX:NewRatio=4 新生代:老年代=1:4 默认值是2也就是1:2
     * -XX:+PrintGCDetails
     *
     * -Xms10m -Xmx10m -XX:NewRatio=4   -XX:+PrintGCDetails
     */
    public static void main(String[] args) {

    }
}

截图分析:

2.3:设置新生代的伊甸、to、from大小

设置年轻代中Eden区与Survivor区的比值。表示2个Survivor区(JVM堆内存年轻代中默认有2个大小相等的Survivor区)与1个Eden区的比值为2:4,即1个Survivor区占整个年轻代大小的1/6。

1:这里设置SurvivorRatio=4,eden:from:to=4:1:1

public class JvmHeadTest2 {
    /**
     * jvm的堆内存设置
     * -XX:SurvivorRatio=4    伊甸:from:to=4:1:1
     *
     * -XX:SurvivorRatio=4 -XX:+PrintGCDetails
     */
    public static void main(String[] args) {

    }
}

截图:

2:这里设置SurvivorRatio=6,eden:from:to=6:1:1

public class JvmHeadTest2 {
    /**
     * jvm的堆内存设置
     * -XX:SurvivorRatio=6    伊甸:from:to=6:1:1
     *
     * -XX:SurvivorRatio=6 -XX:+PrintGCDetails
     */
    public static void main(String[] args) {

    }
}

截图:

3:栈内存设置默认是1M,-Xss2m设置

1:默认栈1M,我们查看代码

public class StackTest1 {
    /**
     * -Xss1m -XX:+PrintGCDetails
     * -Xss1m 每个线程申请的栈的内存是1m,14000的阶乘会报错
     */
    public static void main(String[] args) {
        long n=14000;
        long add = add(n);
        System.out.println(add);
    }

    /**
     * 阶乘算法,n太大,会出现StackOverflowError
     * @param n
     * @return
     */
    public static long add(long n) {
        if (n <= 1) {
            return n; // 终止条件
        } else {
            return n * add(n - 1); // 递归调用
        }
    }
}

报错截图:StackOverflowError

修改栈的大小

-Xss2m -XX:+PrintGCDetails

这时候在测试,不报错了,线程的栈空间更大,能容纳更多此次的递归调用。

 

4:元空间大小设置默认21M,自动扩展

默认的 MetaspaceSize=21807104=21M

原来JDK8中,XX:MaxMetaspaceSize确实是没有上限的,最大容量与机器的内存有关;但是XX:MetaspaceSize是有一个默认值的:21M

1:字段定义元空间大小

-XX:MetaspaceSize=200m -XX:MaxMetaspaceSize=200m -XX:+PrintGCDetails
public class MetaspaceSizeTest1 {
    /**
     *
     * -XX:MetaspaceSize=200m -XX:MaxMetaspaceSize=200m -XX:+PrintGCDetails
     * 自定义元空间的大小
     */
    public static void main(String[] args) {

    }
}

输出结果好像没有变化?挠头

5:其它JVM参数

-XX:MaxTenuringThreshold=15 对象在年轻代的GC回收次数,超过15次没有回收,进入老年代

6:JVM调优

6.1:visualvm调优

注意:在高版本的 JDK 中(JDK >= 9) 已经移除了该文件,如果高版本的 JDK 需要使用该工具,需要额外下载,下载地址:VisualVM: Download,下载完成后双击 bin 目录下的 visualvm.exe 文件启动 VisualVM

VisualVm是一个功能强大的多合一故障诊断工具和性能监控可视化工具。这款工具不仅提供了内存使用、线程活动和 CPU 占用等方面的实时数据,还能通过分析堆转储(heap dump)来识别内存泄漏。尽管 Java VisualVM 的功能强大,但很多开发者在启动和使用过程中会感到困惑。本文将介绍如何打开 Java VisualVM,并用实例说明如何解决一个实际问题

主要有两个途径

1:在idea中进行安装VisualVm插件

2:在自己的电脑中独自安装

补充:需要安装VisualGC插件便于查看堆的内存信息

6.2:实时监控内存溢出OOM

参数设置 -Xms100m -Xmx100m -Xmn40m -XX:+PrintGCDetails

 /**
     * 模拟内存占用高  
     * -Xms100m -Xmx100m -Xmn40m -XX:+PrintGCDetails
     * 堆内存初始值和最大都是100M 年轻代40M
     * 
     * java.lang.OutOfMemoryError: Java heap space
     */
    @GetMapping(value = "get2")
    public List<User> select(@RequestParam(value = "id",required = false) Integer id) {
        List<User> users = new ArrayList<>();
        //死循环  很快就是把堆内存占满
        while (true){
            User user = new User();
            users.add(user);
        }
    }

发送请求截图分析:

6.3:日志监控内存溢出OOM案例

实时监控优缺点,发生OOM的时候我们不一定能及时看到。因此我们希望在服务器发生OOM的时候能保存日志,便于追踪分析

1.设置参数在异常发生时自动生成dump文件。

-XX:+HeapDumpOnOutOfMemoryError 表示当JVM发生OOM时,自动生成DUMP文件。

-XX:HeapDumpPath=存储文件/目录 表示生成DUMP文件的路径

java代码:

 /**
     * 模拟内存占用高
     * -Xms100m -Xmx100m -Xmn40m -XX:+PrintGCDetails
     * 堆内存初始值和最大都是100M 年轻代40M
     *
     * java.lang.OutOfMemoryError: Java heap space
     *
     * -Xms100m
     * -Xmx100m
     * -Xmn40m
     * -XX:+HeapDumpOnOutOfMemoryError 设置oom的时候自动输出dump
     * -XX:HeapDumpPath=/Users/huyiju/Desktop/JVM/a.dump 设置文件位置
     * -XX:+PrintGCDetails
     */
    @GetMapping(value = "get2")
    public List<User> select2() {
        List<User> users = new ArrayList<>();
        //很快就是把堆内存占满
        while (true){
            User user = new User();
            users.add(user);
        }
    }

分析截图:查看那些对象OOM了

6.4:CPU占用高的时候

Java代码:

/**
     * 模拟cpu占用高
     * @param id
     */
    @GetMapping(value = "get3")
    public void select3(@RequestParam(value = "id",required = false) Integer id) {
        while (true){

        }
    }

vm分析:

精准定位到方法,该方法是死循环。

6.5:服务器cpu占用高 

第1步,使用top命令找到占用CPU高的进程。

第2步,使用ps –mp命令找到进程下占用CPU高的线程ID。

第3步,使用printf命令将线程ID转换成十六进制数。

第4步,使用jstack命令输出线程运行状态的日志信息。

https://zhuanlan.zhihu.com/p/641072716

6.6:visualvm连接服务器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值