当前位置: 首页 > news >正文

闲谈JVM(一):浅析JVM Heap参数配置

文章目录

  • 前言
  • JVM内存模型
  • 堆(Heap)配置
    • Xms与InitialHeapSize
    • Xmx与MaxHeapSize
    • Heap的缺省配置
        • Default Heap Size
        • Client JVM Default Initial and Maximum Heap Sizes
        • Server JVM Default Initial and Maximum Heap Sizes
  • 堆(Heap)的动态调整
  • Heap大小配置建议
  • 结语

前言

JVM是Java语言的核心基石所在,它为Java提供了强大的跨平台能力,关于JVM的内部结构,想必您并不陌生,有大量的文章来介绍JVM的内部组成结构,本篇的重点不在于此,这里假定您对JVM的内部组成结构已经比较了解。

JVM中提供了大量的配置参数,通过JVM的参数配置,可以让JVM的性能更加适配于应用服务,发挥出更加强大的性能,那么本篇,就来简单聊一下JVM的参数配置,首先,来看一下JVM堆区的配置。

JVM内存模型

堆区示意图

上图就是JVM的内存模型,JVM内存结构主要有三大块:堆内存方法区

对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存

堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分成三部分,Eden空间From Survivor空间To Survivor空间

我们首先来看其中最为重要的一个部分,堆(Heap)区。

堆(Heap)配置

按照官方的说法:“Java 虚拟机具有一个堆(Heap),堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”

堆区的大小,主要由以下几个参数进行控制:

1、Xms

2、Xmx

3、MaxHeapSize

4、InitalHeapSize

我们来分别看一下这几个参数各自的用途。

Xms与InitialHeapSize

Xms等价于InitialHeapSize,表示Heap的初始化大小,即JVM启动时,堆区的最小值,使用该参数的正确姿势是:

-Xms10m

-XX:InitialHeapSize=10m

那么这个Heap的最小值的设定的意义,即JVM进行GC垃圾回收时,会对Heap进行清理,会对Heap的内存进行缩容的操作,那么缩容最小是缩到多小,这个值就是缩容可以缩到的最小内存值。

一般在实际的生产应用中,Xms的大小配置,一般与Xmx设置为同一个值,避免JVM GC执行时频繁进行扩容缩容操作。

需要注意的是,InitialHeapSize的最小值是1M,如果小于这个值,JVM启动会报错。

虽然Xms与InitialHeapSize表示的含义是相同的,但是这两个参数如果同时设置,那么生效的只有最后设置的参数。

Xmx与MaxHeapSize

Xmx等价于MaxHeapSize,表示Heap的最大值大小,即Heap区可以分配使用最大内存值,使用该参数的正确姿势是:

-Xmx100m

-XX:MaxHeapSize=100m

这里需要注意的是,MaxHeapSize与InitialHeapSize的关系,MaxHeapSize是必须要大于等于InitialHeapSize的,否则JVM无法启动,我们来验证一下这个说法是否正确。

实验,我们来写一个简单的Demo:

public class HelloWorld {
	public static void main(String[] args) {
		try {
			Thread.sleep(1000 * 60);
		} catch(Exception e) {
			System.out.println("Error");
		}
		System.out.println("hello world");
	}
}

设定JVM参数:

-Xms100m -Xmx10m

运行:

java -Xms100m -Xmx10m  HelloWorld

执行结果:

Error occurred during initialization of VM
Initial heap size set to a larger value than the maximum heap size

Heap的缺省配置

上面我们介绍了Heap的大小设置的参数的使用规则,那么如果我们没有设置Heap的大小,JVM会如何设定呢?

我们来看一下Java8中Oracle的官方说法:

Default Heap Size

Unless the initial and maximum heap sizes are specified on the command line, they are calculated based on the amount of memory on the machine.

Client JVM Default Initial and Maximum Heap Sizes

The default maximum heap size is half of the physical memory up to a physical memory size of 192 megabytes (MB) and otherwise one fourth of the physical memory up to a physical memory size of 1 gigabyte (GB).

For example, if your computer has 128 MB of physical memory, then the maximum heap size is 64 MB, and greater than or equal to 1 GB of physical memory results in a maximum heap size of 256 MB.

The maximum heap size is not actually used by the JVM unless your program creates enough objects to require it. A much smaller amount, called the initial heap size, is allocated during JVM initialization. This amount is at least 8 MB and otherwise 1/64th of physical memory up to a physical memory size of 1 GB.

The maximum amount of space allocated to the young generation is one third of the total heap size.

Server JVM Default Initial and Maximum Heap Sizes

The default initial and maximum heap sizes work similarly on the server JVM as it does on the client JVM, except that the default values can go higher. On 32-bit JVMs, the default maximum heap size can be up to 1 GB if there is 4 GB or more of physical memory. On 64-bit JVMs, the default maximum heap size can be up to 32 GB if there is 128 GB or more of physical memory. You can always set a higher or lower initial and maximum heap by specifying those values directly; see the next section.

根据Oracle官方文档的说法,JVM的默认堆大小如果未指定,它将会根据服务器物理内存计算而来的。

client模式下,JVM初始和最大堆大小为:
在物理内存达到192MB之前,JVM最大堆大小为物理内存的一半,否则,在物理内存大于192MB,在到达1GB之前,JVM最大堆大小为物理内存的1/4,大于1GB的物理内存也按1GB计算,举个例子,如果你的电脑内存是128MB,那么最大堆大小就是64MB,如果你的物理内存大于或等于1GB,那么最大堆大小为256MB。
Java初始堆大小是物理内存的1/64,但最小是8MB。

server模式下:
与client模式类似,区别就是默认值可以更大,比如在32位JVM下,如果物理内存在4G或更高,最大堆大小可以提升至1GB,,如果是在64位JVM下,如果物理内存在128GB或更高,最大堆大小可以提升至32GB。

堆(Heap)的动态调整

JVM在启动之后,整个Heap的大小虽然是固定的,但是并不代表整个堆里的内存都可用,在GC之后会根据一些参数进行动态的调整,比如我们设置Xmx和Xms不一样的时候,就表示堆里的新生代和老生代的可用内存都是存在不断变化的。

所以需要提一个概念,叫做相关堆的有效内存,这里的相关堆可以是指新生代,也可以是老生代,甚至整个堆,有效内存表示真正可用的内存。

一般来说,稳定的堆大小对垃圾回收是有利的。获得一个稳定的堆大小的方法是使-Xms 和-Xmx 的大小一致,即最大堆和最小堆 (初始堆) 一样。

如果这样设置,系统在运行时堆大小理论上是恒定的,稳定的堆空间可以减少 GC 的次数。因此,很多服务端应用都会将最大堆和最小堆设置为相同的数值。

但是,一个不稳定的堆并非毫无用处。稳定的堆大小虽然可以减少 GC 次数,但同时也增加了每次 GC 的时间。让堆大小在一个区间中震荡,在系统不需要使用大内存时,压缩堆空间,使 GC 应对一个较小的堆,可以加快单次 GC 的速度。基于这样的考虑,JVM 还提供了两个参数用于压缩和扩展堆空间。

-XX:MinHeapFreeRatio 参数用来设置堆空间最小空闲比例,默认值是 40。当堆空间的空闲内存小于这个数值时,JVM 便会扩展堆空间。

-XX:MaxHeapFreeRatio 参数用来设置堆空间最大空闲比例,默认值是 70。当堆空间的空闲内存大于这个数值时,便会压缩堆空间,得到一个较小的堆。

不过需要注意的是,当-Xmx 和-Xms 相等时,-XX:MinHeapFreeRatio 和-XX:MaxHeapFreeRatio 两个参数无效。

在实际生产环境中,如果不是对JVM Heap的情况极为了解,不建议设置该参数。

仍是建议将-Xms与-Xmx的大小设置为一样值,避免Heap的大小扩张缩小。

Heap大小配置建议

在生产环境中,我们的应用上线之前,一定是需要JVM参数的配置,那么,JVM的Heap区大小的设置,多大是合理的值呢?

这里我们给出三种常见的服务器配置,对应的Heap的配置参数,仅供参考。

1、4核8G Linux64位 JDK8

-Xmx5440M -Xms5440M -XX:MaxMetaspaceSize=512M -XX:MetaspaceSize=512M 
-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:+ParallelRefProcEnabled

2、2核4G Linux64位 JDK8

-Xmx2688M -Xms2688M -Xmn960M -XX:MaxMetaspaceSize=512M -XX:MetaspaceSize=512M 
-XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 
-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses -XX:+CMSClassUnloadingEnabled 
-XX:+ParallelRefProcEnabled -XX:+CMSScavengeBeforeRemark

3、4核16G Linux64位 JDK8

-Xmx10880M -Xms10880M -XX:MaxMetaspaceSize=512M -XX:MetaspaceSize=512M 
-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:+ParallelRefProcEnabled

结语

本篇,我们介绍了JVM Heap的相关配置参数,Heap的配置可以说是JVM参数配置中最重要的部分之一,Heap大小需要根据实际服务器与应用的情况来综合考量,过大的堆区会对GC带来较大的压力,从而导致STW时间加长,过小的堆区会导致内存空间不足,JVM需要频繁的GC来清理空间,也可能导致OOM,因此合理的Heap大小是非常重要的。

下一篇中,我们会对Heap进一步深入,看一下Heap的重要组成部分,新生代Heap的配置,敬请期待。

相关文章:

  • 商城小程序系统,商城源码
  • 元宇宙电商-NFG系统带你布局数字藏品领域
  • statsD学习笔记
  • 坠落的蚂蚁(暑假每日一题 40)
  • TV蓝牙无法被搜索问题解决记录:REQUEST_DISCOVERABLE ActivityNotFoundException
  • 【JavaScript 逆向】猿人学 web 第六题:回溯
  • 最牛逼的 Java 日志框架,性能无敌,横扫所有对手
  • CREO:CREO软件之装配设计界面的简介、装配图设计流程、案例应用(图文教程)之详细攻略
  • 【赛码网刷题】动态规划之上台阶
  • Java 的开发效率究竟比 C++ 高在哪里?
  • python random应用实例 从可选池随机选取指定个数的元素并随机排序
  • 【Java成王之路】EE初阶第二十二篇 博客系统(页面设计)
  • 编译mtd-utils(使用uclibc编译)
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • springboot网络安全考核平台设计毕业设计源码042335
  • 78. Subsets
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • Laravel 菜鸟晋级之路
  • Making An Indicator With Pure CSS
  • MySQL-事务管理(基础)
  • Node项目之评分系统(二)- 数据库设计
  • vue-router 实现分析
  • web标准化(下)
  • XML已死 ?
  • 复杂数据处理
  • 来,膜拜下android roadmap,强大的执行力
  • 前端代码风格自动化系列(二)之Commitlint
  • 实现简单的正则表达式引擎
  • 使用SAX解析XML
  • 算法-插入排序
  • 微信公众号开发小记——5.python微信红包
  • 一文看透浏览器架构
  • 原生 js 实现移动端 Touch 滑动反弹
  • 怎样选择前端框架
  • 正则学习笔记
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #DBA杂记1
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (4)STL算法之比较
  • (AngularJS)Angular 控制器之间通信初探
  • (pojstep1.3.1)1017(构造法模拟)
  • (笔试题)合法字符串
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (南京观海微电子)——COF介绍
  • (十三)Flask之特殊装饰器详解
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (转)Google的Objective-C编码规范
  • (转)可以带来幸福的一本书