常用JVM配置参数

news2024/12/24 21:11:31

在IDE的后台打印GC日志:

既然学习JVM,阅读GC日志是处理Java虚拟机内存问题的基础技能,它只是一些人为确定的规则,没有太多技术含量。

既然如此,那么在IDE的控制台打印GC日志是必不可少的了。现在就告诉你怎么打印。

(1)如果你用的是Eclipse,打印GC日志的操作如下:

d32742cf-b002-4c55-a185-d4ccdc90a69c

bc5b8afb-9d1f-438b-9225-ee7fbbbe2454

在上图的箭头处加上-XX:+PrintGCDetails这句话。于是,运行程序后,GC日志就可以打印出来了:

25d80649-69f0-47b2-a3bb-418ba4457849

(2)如果你用的是IntelliJ IDEA,打印GC日志的操作如下:

94726055-e81f-45b8-8978-d1277c5acb17

f2c896da-404c-4415-98ef-5b582dec3528

在上图的箭头处加上-XX:+PrintGCDetails这句话。于是,运行程序后,GC日志就可以打印出来了:

6b1b4352-7172-4404-ac6c-b94c16036d73

当然了,光有-XX:+PrintGCDetails这一句参数肯定是不够的,下面我们详细介绍一下更多的参数配置。

一、Trace跟踪参数:

1、打印GC的简要信息:

-verbose:gc
-XX:+printGC

解释:可以打印GC的简要信息。比如:

[GC 4790K->374K(15872K), 0.0001606 secs]

[GC 4790K->374K(15872K), 0.0001474 secs]

[GC 4790K->374K(15872K), 0.0001563 secs]

[GC 4790K->374K(15872K), 0.0001682 secs]

上方日志的意思是说,GC之前,用了4M左右的内存,GC之后,用了374K内存,一共回收了将近4M。内存大小一共是16M左右。

2、打印GC的详细信息:

-XX:+PrintGCDetails

解释:打印GC详细信息。

-XX:+PrintGCTimeStamps

解释:打印CG发生的时间戳。

理解GC日志的含义:

例如下面这段日志:

[GC[DefNew: 4416K->0K(4928K), 0.0001897 secs] 4790K->374K(15872K), 0.0002232 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

上方日志的意思是说:这是一个新生代的GC。方括号内部的“4416K->0K(4928K)”含义是:“GC前该内存区域已使用容量->GC后该内存区域已使用容量(该内存区域总容量)”。而在方括号之外的“4790K->374K(15872K)”表示“GC前Java堆已使用容量->GC后Java堆已使用容量(Java堆总容量)”。

再往后看,“0.0001897 secs”表示该内存区域GC所占用的时间,单位是秒。

再比如下面这段GC日志:

1fe41f36-cc6b-4a8b-b48e-8cbe2e3a04af

上图中,我们先看一下用红框标注的“[0x27e80000, 0x28d80000, 0x28d80000)”的含义,它表示新生代在内存当中的位置:第一个参数是申请到的起始位置,第二个参数是申请到的终点位置,第三个参数表示最多能申请到的位置。上图中的例子表示新生代申请到了15M的控件,而这个15M是等于:(eden space的12288K)+(from space的1536K)+(to space的1536K)

3、指定GC log的位置:

-Xloggc:log/gc.log

解释:指定GC log的位置,以文件输出。帮助开发人员分析问题。

805e8e33-1e3b-46c0-af9d-d68f4d38816f

  

-XX:+PrintHeapAtGC

解释:每一次GC前和GC后,都打印堆信息。

例如:

1c6f3837-4b31-4ac2-a639-e79c92f80df5

上图中,红框部分正好是一次GC,红框部分的前面是GC之前的日志,红框部分的后面是GC之后的日志。

-XX:+TraceClassLoading

解释:监控类的加载。

例如:

[Loaded java.lang.Object from shared objects file]

[Loaded java.io.Serializable from shared objects file]

[Loaded java.lang.Comparable from shared objects file]

[Loaded java.lang.CharSequence from shared objects file]

[Loaded java.lang.String from shared objects file]

[Loaded java.lang.reflect.GenericDeclaration from shared objects file]

[Loaded java.lang.reflect.Type from shared objects file]

-XX:+PrintClassHistogram

解释:按下Ctrl+Break后,打印类的信息。

例如:

c8050739-0029-47cd-95bd-fbbd6289a5d1

二、堆的分配参数:

1、-Xmx –Xms:指定最大堆和最小堆

举例、当参数设置为如下时:

-Xmx20m -Xms5m

然后我们在程序中运行如下代码:

System.out.println("Xmx=" + Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");     //系统的最大空间

System.out.println("free mem=" + Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");   //系统的空闲空间

System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");   //当前可用的总空间

 运行效果:

79c1029d-58fe-47d9-aa2e-1c5ee7e741cd

保持参数不变,在程序中运行如下代码:(分配1M空间给数组)

byte[] b = new byte[1 * 1024 * 1024];
System.out.println("分配了1M空间给数组");

System.out.println("Xmx=" + Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");   //系统的最大空间

System.out.println("free mem=" + Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");   //系统的空闲空间

System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");   

运行效果:

14d260c9-28bf-4544-a36f-ee14a1d59623

注:Java会尽可能将total mem的值维持在最小堆。

保持参数不变,在程序中运行如下代码:(分配10M空间给数组)

byte[] b = new byte[10 * 1024 * 1024];
System.out.println("分配了10M空间给数组");

System.out.println("Xmx=" + Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");   //系统的最大空间

System.out.println("free mem=" + Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");   //系统的空闲空间

System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");   //当前可用的总空间

运行效果:

284e8036-8d70-46bc-aac1-99c9b3deb3ef

如上图红框所示:此时,total mem 为7M时已经不能满足需求了,于是total mem涨成了16.5M。

保持参数不变,在程序中运行如下代码:(进行一次GC的回收)

System.gc();

System.out.println("Xmx=" + Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");    //系统的最大空间

System.out.println("free mem=" + Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");   //系统的空闲空间

System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");   //当前可用的总空间 

运行效果:

e419c020-0da3-4046-9b7f-f542ee14a780

问题1: -Xmx(最大堆空间)和 –Xms(最小堆空间)应该保持一个什么关系,可以让系统的性能尽可能的好呢?

问题2:如果你要做一个Java的桌面产品,需要绑定JRE,但是JRE又很大,你如何做一下JRE的瘦身呢?

2、-Xmn、-XX:NewRatio、-XX:SurvivorRatio:

  • -Xmn

    设置新生代大小

  • -XX:NewRatio

    新生代(eden+2*s)和老年代(不包含永久区)的比值

        例如:4,表示新生代:老年代=1:4,即新生代占整个堆的1/5

  • -XX:SurvivorRatio(幸存代)

    设置两个Survivor区和eden的比值

        例如:8,表示两个Survivor:eden=2:8,即一个Survivor占年轻代的1/10

现在运行如下这段代码:

public class JavaTest {
    public static void main(String[] args) {
        byte[] b = null;
        for (int i = 0; i < 10; i++)
            b = new byte[1 * 1024 * 1024];
    }
}

我们通过设置不同的jvm参数,来看一下GC日志的区别。

 

(1)当参数设置为如下时:(设置新生代为1M,很小)

-Xmx20m -Xms20m -Xmn1m -XX:+PrintGCDetails 

运行效果:

4f0b24b4-cc74-4fd6-af15-b30a784d351b

总结:

  没有触发GC

    由于新生代的内存比较小,所以全部分配在老年代。

(2)当参数设置为如下时:(设置新生代为15M,足够大)

-Xmx20m -Xms20m -Xmn15m -XX:+PrintGCDetails

运行效果:

2cb6145f-8c1b-4269-bcfa-31912d2f0d41

上图显示:

没有触发GC

全部分配在eden(蓝框所示)

老年代没有使用(红框所示)

(3)当参数设置为如下时:(设置新生代为7M,不大不小)

-Xmx20m -Xms20m –Xmn7m -XX:+PrintGCDetails

运行效果:

0e0cc65d-e291-477a-ba7f-7d433f1085cc

总结:

  进行了2次新生代GC

  s0 s1 太小,需要老年代担保

(4)当参数设置为如下时:(设置新生代为7M,不大不小;同时,增加幸存代大小)

-Xmx20m -Xms20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails

运行效果:

35eb96d6-9251-45e5-8120-05b82210df06

总结:

    进行了至少3次新生代GC

    s0 s1 增大

(5)当参数设置为如下时:

-Xmx20m -Xms20m -XX:NewRatio=1

-XX:SurvivorRatio=2 -XX:+PrintGCDetails 

运行效果:

c85f7057-1842-4d11-bc28-fc766e5681f8

(6)当参数设置为如下时: 和上面的(5)相比,适当减小幸存代大小,这样的话,能够减少GC的次数

-Xmx20m -Xms20m -XX:NewRatio=1

-XX:SurvivorRatio=3 -XX:+PrintGCDetails

fd3322ec-a853-49aa-86fa-81d8b3a02f8c

3、-XX:+HeapDumpOnOutOfMemoryError、-XX:+HeapDumpPath

  • -XX:+HeapDumpOnOutOfMemoryError

    OOM时导出堆到文件

      根据这个文件,我们可以看到系统dump时发生了什么。

  • -XX:+HeapDumpPath

    导出OOM的路径

例如我们设置如下的参数:

-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump

上方意思是说,现在给堆内存最多分配20M的空间。如果发生了OOM异常,那就把dump信息导出到d:/a.dump文件中。

然后,我们执行如下代码:

Vector v = new Vector();
for (int i = 0; i < 25; i++)
  v.add(new byte[1 * 1024 * 1024]);

上方代码中,需要利用25M的空间,很显然会发生OOM异常。现在我们运行程序,控制台打印如下:

3320aba5-2aa6-42bc-b656-57bbc5d8ec41

现在我们去D盘看一下dump文件:

8782a0ae-62fb-43a8-a5a6-1c5691e7fa59

上图显示,一般来说,这个文件的大小和最大堆的大小保持一致。

我们可以用VisualVM打开这个dump文件。

注:关于VisualVM的使用,可以参考下面这篇博客:

使用 VisualVM 进行性能分析及调优:IBM Developer

或者使用Java自带的Java VisualVM工具也行:

f9158d50-95d0-4732-942c-e872181fa530

f69bd0d2-a355-4a93-81c1-c3e71bce7509

上图中就是dump出来的文件,文件中可以看到,一共有19个byte已经被分配了。 

4、-XX:OnOutOfMemoryError:

  • -XX:OnOutOfMemoryError

    在OOM时,执行一个脚本。

      可以在OOM时,发送邮件,甚至是重启程序。

例如我们设置如下的参数:

-XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/printstack.bat %p //p代表的是当前进程的pid 

上方参数的意思是说,执行printstack.bat脚本,而这个脚本做的事情是:D:/tools/jdk1.7_40/bin/jstack -F %1 > D:/a.txt,即当程序OOM时,在D:/a.txt中将会生成线程的dump。

5、堆的分配参数总结:

  • 根据实际事情调整新生代和幸存代的大小
  • 官方推荐新生代占堆的3/8
  • 幸存代占新生代的1/10
  • 在OOM时,记得Dump出堆,确保可以排查现场问题

 

6、永久区分配参数:

  • -XX:PermSize  -XX:MaxPermSize

    设置永久区的初始空间和最大空间。也就是说,jvm启动时,永久区一开始就占用了PermSize大小的空间,如果空间还不够,可以继续扩展,但是不能超过MaxPermSize,否则会OOM。

    他们表示,一个系统可以容纳多少个类型

代码举例:

我们知道,使用CGLIB等库的时候,可能会产生大量的类,这些类,有可能撑爆永久区导致OOM。于是,我们运行下面这段代码:

for(int i=0;i<100000;i++){
  CglibBean bean = new CglibBean("geym.jvm.ch3.perm.bean"+i,new HashMap());
}

上面这段代码会在永久区不断地产生新的类。于是,运行效果如下:

fd7bcefb-d6d5-4fe0-8d77-9cddae2733fc

总结:

  如果堆空间没有用完也抛出了OOM,有可能是永久区导致的

    堆空间实际占用非常少,但是永久区溢出 一样抛出OOM。

三、栈的分配参数:

1、Xss:

设置栈空间的大小。通常只有几百K

  决定了函数调用的深度

  每个线程都有独立的栈空间

  局部变量、参数 分配在栈上

注:栈空间是每个线程私有的区域。栈里面的主要内容是栈帧,而栈帧存放的是局部变量表,局部变量表的内容是:局部变量、参数。

我们来看下面这段代码:(没有出口的递归调用)

public class TestStackDeep {
    private static int count = 0;

    public static void recursion(long a, long b, long c) {
        long e = 1, f = 2, g = 3, h = 4, i = 5, k = 6, q = 7, x = 8, y = 9, z = 10;
        count++;
        recursion(a, b, c);
    }

    public static void main(String args[]) {
        try {
            recursion(0L, 0L, 0L);
        } catch (Throwable e) {
            System.out.println("deep of calling = " + count);
            e.printStackTrace();
        }
    }
}

上方这段代码是没有出口的递归调用,肯定会出现OOM的。

如果设置栈大小为128k:

-Xss128K 

运行效果如下:(方法被调用了294次)

5c2b2060-e54a-4e7c-9a30-81567204d55b

如果设置栈大小为256k:(方法被调用748次)

7d6be7d6-b646-42bf-9357-1a3bccbb7a49

意味着函数调用的次数太深,像这种递归调用就是个典型的例子。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1002330.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Django03_Django基本配置

Django03_Django基本配置 3.1 整体概述 django项目创建后&#xff0c;在主应用中&#xff0c;会有一个settings.py文件&#xff0c;这个就是该项目的配置文件 settings文件包含Django安装的所有配置settings文件是一个包含模块级变量的python模块&#xff0c;所以该模块本身必…

解决nbsp;不生效的问题

代码块 {{title}} title:附 \xa0\xa0\xa0件,//或者 <span v-html"title"></span> title:附 件&#xff1a;,效果图

青骨申报|CSC管理信息平台使用指南

2023年青年骨干教师出国研修项目于9月10-25日网上报名&#xff0c;为此知识人网小编特转载最新版本的国家留学基金委&#xff08;CSC&#xff09;国家公派留学管理信息平台使用指南&#xff08;国内申请访学类&#xff09;&#xff0c;以方便申报者查阅。 提示&#xff1a;国家…

静态代理和动态代理笔记

总体分为: 1.静态代理: 代理类和被代理类需要实现同一个接口.在代理类中初始化被代理类对象.在代理类的方法中调 用被代理类的方法.可以选择性的在该方法执行前后增加功能或者控制访问 2.动态代理: 在程序执行过程中,实用JDK的反射机制,创建代理对象,并动态的指定要…

数字档案管理系统单机版功能

nhdeep数字档案管理系统&#xff0c;简化了档案库配置过程&#xff0c;内置标准著录项&#xff0c;点击创建新档案库后选择档案库类型为案卷库或一文一件库后&#xff0c;可立即使用此档案库&#xff1b; 支持添加额外的自定义著录项&#xff0c;支持批量数据导入&#xff0c;…

读高性能MySQL(第4版)笔记06_优化数据类型(上)

1. 良好的逻辑设计和物理设计是高性能的基石 1.1. 反范式的schema可以加速某些类型的查询&#xff0c;但同时可能减慢其他类型的查询 1.2. 添加计数器和汇总表是一个优化查询的好方法&#xff0c;但它们的维护成本可能很 1.3. 将修改schema作为一个常见事件来规划 2. 让事情…

JVM GC垃圾回收

一、GC垃圾回收算法 标记-清除算法 算法分为“标记”和“清除”阶段&#xff1a;标记存活的对象&#xff0c; 统一回收所有未被标记的对象(一般选择这种)&#xff1b;也可以反过来&#xff0c;标记出所有需要回收的对象&#xff0c;在标记完成后统一回收所有被标记的对象 。它…

二分搜索树节点删除(Java 实例代码)

目录 二分搜索树节点删除 src/runoob/binary/BSTRemove.java 文件代码&#xff1a; 二分搜索树节点删除 本小节介绍二分搜索树节点的删除之前&#xff0c;先介绍如何查找最小值和最大值&#xff0c;以及删除最小值和最大值。 以最小值为例&#xff08;最大值同理&#xff09…

在 Simscape Electrical 中对两区 MVDC 电动船的建模和仿真(Simulink实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Linux Centos7内网服务器离线升级openssh9.3

内网服务器需要升级openssh&#xff0c;被折磨了一整天&#xff0c;觉得有必要记录一下&#xff0c;不然对不起这差点崩溃的一天&#xff0c;主要的几个难点就是不能yum一键安装&#xff0c;需要自己找到对应的依赖版本然后通过堡垒机上传到内网&#xff0c;还有就是服务器很干…

无涯教程-JavaScript - ISPMT函数

描述 ISPMT函数计算在特定投资期间支付的利息。提供此功能是为了与Lotus 1-2-3兼容。 语法 ISPMT (rate, per, nper, pv)争论 Argument描述Required/OptionalRateThe interest rate for the investment.RequiredPerThe period for which you want to find the interest, an…

vue-puzzle-vcode完成验证码拖拽

一、 vue-puzzle-vcode插件【推荐】 GitHub地址&#xff1a;beeworkshop/vue-puzzle-vcode 1、安装vue-puzzle-vcode cnpm i -S vue-puzzle-vcode2、实现代码 <template><div><Vcode :show"isShow" success"success" close"close&…

7年经验之谈 —— Web测试是什么,有何特点?

Web测试是指对Web应用程序进行验证和评估的过程&#xff0c;以确保其功能、性能和安全性符合预期。 Web测试具体包括以下几个方面的内容&#xff1a; 功能测试&#xff1a;验证Web应用程序是否按照需求规格说明书中定义的功能正常工作。功能测试包括输入验证、表单提交、页面…

【Flutter】Flutter 使用 pull_to_refresh 实现下拉刷新和上拉加载

【Flutter】Flutter 使用 pull_to_refresh 实现下拉刷新和上拉加载 文章目录 一、前言二、pull_to_refresh 包简介三、安装与基本使用四、高级功能与配置五、实际业务中的用法六、完整示例七、总结 一、前言 你好&#xff01;在移动开发中&#xff0c;下拉刷新和上拉加载是非常…

【数据结构】双向链表详解

当我们学习完单链表后&#xff0c;双向链表就简单的多了&#xff0c;双向链表中的头插&#xff0c;尾插&#xff0c;头删&#xff0c;尾删&#xff0c;以及任意位置插&#xff0c;任意位置删除比单链表简单&#xff0c;今天就跟着小张一起学习吧&#xff01;&#xff01; 双向链…

Pytorch Advanced(一) Generative Adversarial Networks

生成对抗神经网络GAN&#xff0c;发挥神经网络的想象力&#xff0c;可以说是十分厉害了 参考 1、AI作家 2、将模糊图变清晰(去雨&#xff0c;去雾&#xff0c;去抖动&#xff0c;去马赛克等)&#xff0c;这需要AI具有“想象力”&#xff0c;能脑补情节&#xff1b; 3、进行数…

JavaScript Promise 的真正工作原理

Promise 是处理异步代码的一种技术,也称为脱离回调地狱的头等舱门票。 3 承诺状态 待定状态 已解决状态 拒绝状态 理解 JavaScript Promis 什么是承诺? 通常,承诺被定义为最终可用的值的代理。 Promise 多年来一直是 JavaScript 的一部分(在 ES2015 中标准化并引入)。最…

【数据结构】前言概况 - 树

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;数据结构 &#x1f525;该文章针对树形结构作出前言&#xff0c;以保证可以对树初步认知。 目录&#xff1a; &#x1f30d;前言:&#x1f3…

Python语义分割与街景识别(4):程序运行

前言 本文主要用于记录我在使用python做图像识别语义分割训练集的过程&#xff0c;由于在这一过程中踩坑排除BUG过多&#xff0c;因此也希望想做这部分内容的同学们可以少走些弯路。 本文是python语义分割与街景识别第四篇&#xff0c;关于程序的内容&#xff0c;也是差不多最…

【Unity编辑器扩展】| GameView面板扩展

前言【Unity编辑器扩展】| GameView面板扩展未运行时在Game视图进行绘制总结前言 前面我们介绍了Unity中编辑器扩展的一些基本概念及基础知识,还有编辑器扩展中用到的相关特性Attribute介绍。后面就来针对Uniity编辑器扩展中比较常用的模块进行学习介绍。本文就来详细介绍一下…