网站首页 > 技术文章 正文
前言
在网上看到大部分的帖子都有介绍性能调优的案例,其中有一项就是告诉你 Xms 和 Xmx 参数一定要设置成相同的,这样就可以达到优化的目的,就像这样
-Xms1024m -Xmx1024m
但是却没说为什么要这么设置,那么这篇文章就是来告诉你这样设置的目的。底层做了哪些事情。
jvm性能调优的最基本条件
首先我们要知道,垃圾回收器(GC)在回收内存空间时候,所有的工作线程都会暂停,待回收工作完成后,工作线程才会继续运行。如果GC太频繁,工作线程的效率和响应时间肯定会受影响,所以,jvm性能调优的最基本条件就是要尽可能地减少垃圾回收的次数。
那么说到这里,jvm性能调优跟内存抖动有什么关系呢?跟Xms和Xmx又有什么关联呢?往下看,你就会知道,他们都是息息相关的!
Xms和Xmx参数为什么要设置相同的值
首先来看看Xms和Xmx的作用
- Xms:堆内存的最小Heap值,默认为物理内存的1/64,但小于1G。默认当空余堆内存大于指定阈值时,JVM会减小heap的大小到-Xms指定的大小。比如我电脑内存是16G,那么默认的Xms就是 16*1024/64=256m
- Xmx:堆内存的最大Heap值,默认为物理内存的1/4。默认当空余堆内存小于指定阈值时,JVM会增大Heap到-Xmx指定的大小。比如我电脑内存是16G,那么默认的Xmx就是16/4=4G
Xms和Xmx不同值产生的内存抖动
其实Xms和Xmx参数设置成相同的值就是为了防止 内存抖动, 如果将Xms和Xmx参数设置为不同的值,比如将堆内存的初始值设置为256m,将最大值设为 4096m
-Xms256m -Xmx4096m
当项目在运行 过程中,
- 默认空余堆内存小于40%时,就会进行扩容,注意这里是提前扩容的,不是达到256m的时候才扩容,跟HashMap类似,博主猜测里面应该也是有一个负载因子类似的参数;只要你一直往塞对象,堆内存就会向操作系统申请内存,基本上是要多少就申请多少,一直到达最大内存(Xmx)
- 空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。
代码示例内存抖动
以下代码测试内存抖动,在项目一开始运行时,默认的的堆内存大小为256m(mac电脑计算内存的方式会有差异,所以显示的实际内存为245m),运行项目后,每隔2秒就会往list对象插入一个占用100M内存的对象,因为初始内存只有245m,所以每次都需要向操作系统申请新的内存来给对象使用;Runtime.getRuntime().totalMemory()这个方法会打印向操作系统申请到的内存总数。
package com.gc;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
*
*在网上看到大部分的帖子都有介绍性能调优的案例,其中有一项就是告诉你 **`Xms`** 和 **`Xmx`** 参数一定要设置成相同的,这样就可以达到优化的目的,就像这样
*-Xms1024m -Xmx1024m
*但是却没说为什么要这么设置,那么这就是来告诉你这样设置的目的
*/
public class XmxAndXms {
public static void main(String[] args) throws InterruptedException {
XmxAndXms test = new XmxAndXms();
// 添加内存前先打印默认的堆内存情况
test.showHeapSpace();
// 开始添加内存
test.addMemory();
}
/**
* 展示堆空间大小
*/
public void showHeapSpace(){
// 每次增加对象时,totalMemory都会增大100倍
System.out.print("当前堆内存:" + Runtime.getRuntime().totalMemory()/1024/1024 + "M") ;
System.out.print(",最大内存:"+Runtime.getRuntime().maxMemory()/1024/1024+ "M");
System.out.print(",空闲内存:" + Runtime.getRuntime().freeMemory()/1024/1024+ "M");
System.out.println();
}
/**
* 每2秒钟往堆内存添加一个占用100m内存的对象
* @throws InterruptedException
*/
public void addMemory() throws InterruptedException {
List<byte[]> list = new ArrayList<>();
for (int j = 0; j < 10; j++) {
System.out.print("第"+(j+ 1)+"次添加内存");
// 每2秒增加100M内存
list.add(new byte[1024 * 1024 * 100]);
// 添加完后展示内存大小
this.showHeapSpace();
TimeUnit.SECONDS.sleep(2);
}
}
}
打印结果如下
当前堆内存:245M,最大内存:3641M,空闲内存:240M
第1次添加内存当前堆内存:245M,最大内存:3641M,空闲内存:140M
第2次添加内存当前堆内存:346M,最大内存:3641M,空闲内存:138M
第3次添加内存当前堆内存:446M,最大内存:3641M,空闲内存:138M
第4次添加内存当前堆内存:547M,最大内存:3641M,空闲内存:139M
第5次添加内存当前堆内存:647M,最大内存:3641M,空闲内存:139M
第6次添加内存当前堆内存:748M,最大内存:3641M,空闲内存:140M
第7次添加内存当前堆内存:848M,最大内存:3641M,空闲内存:140M
第8次添加内存当前堆内存:949M,最大内存:3641M,空闲内存:141M
第9次添加内存当前堆内存:1049M,最大内存:3641M,空闲内存:141M
第10次添加内存当前堆内存:1150M,最大内存:3641M,空闲内存:142M
我们主要看当前堆内存的值,可以看到一开始是245M,当我添加了100M的对象后,每2秒钟就多了 100M左右,每次多出来的100M内存就是jvm向操作系统申请的内存;网上有的帖子说是jvm向操作系统挖过来的内存,其实意思都一样;每次申请内存时的时序图如下
为什么要防止内存抖动
上面已经说过,Xms和Xmx参数设置成相同的值就是为了防止 内存抖动,为什么要防止内存抖动呢? 是因为每次jvm向操作系统申请内存时都需要一定的开销,
就比如我上街看到一个很喜欢的商品,想要买下这个商品,但是我身上的钱不够了, 于是我向你借钱,你同意了,然后你掏出钱包, 把钱拿出来,然后再交给我,你拿钱给我的这整个过程也是需要时间的。所以我为了省下这个拿钱的时间,我在一开始出门的时候就直接带上足够的钱,这样就可以省下借钱的时间了;
jvm也一样,在启动项目的时候就直接设置好足够的堆内存大小,避免不够用的时候又要跟操作系统申请;省下了申请内存的开销,就达到了优化的目的。
完
下次有人问你为什么Xms和Xmx参数设置成相同的值,你和他这样说,这样就明白了。
原文链接:https://blog.csdn.net/qq_27184497/article/details/119052930
猜你喜欢
- 2024-10-28 美团面试:熟悉哪些JVM调优参数,幸好我准备过
- 2024-10-28 Java虚拟机:Jvm概念和原理详解以及GC机制的分析
- 2024-10-28 JVM 的内存模型(jvm1.8内存模型)
- 2024-10-28 JDK、JRE、JVM,是什么关系?(jdk jrejvm的区别)
- 2024-10-28 一个 JVM 参数引发的频繁 CMS GC(当产生一个异常时,jvm会做什么)
- 2024-10-28 JVM系列一:JVM内存组成及分配(jvm的内存分配)
- 2024-10-28 谈谈JMM与JVM的相关知识(jmm jvm juc)
- 2024-10-28 常见的JVM参数配置(常见的JVM参数配置有哪些)
- 2024-10-28 一份详细介绍JVM的资料(对比JDK8和JDK7)
- 2024-10-28 理解JVM运行时数据区域,看这一篇文章就够了
- 11-26Win7\8\10下一条cmd命令可查得笔记本电脑连接过的Wifi密码
- 11-26一文搞懂MySQL行锁、表锁、间隙锁详解
- 11-26电脑的wifi密码忘记了?一招教你如何找回密码,简单明了,快收藏
- 11-26代码解决忘记密码问题 教你用CMD命令查看所有连接过的WIFI密码
- 11-26CMD命令提示符能干嘛?这些功能你都知道吗?
- 11-26性能测试之慢sql分析
- 11-26论渗透信息收集的重要性
- 11-26如何查看电脑连接过的所有WiFi密码
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)