JVM 中最重要的一部分就是堆空间了,基本上大多数的线上 JVM 问题都是因为堆空间造成的 OutOfMemoryError。因此掌握 JVM 关于堆空间的参数配置对于排查线上问题非常重要。

tips:本文所有配置,如无特别说明,均基于JDK1.8。

堆配置

我们使用 -Xms 设置堆的初始空间大小,使用 -Xmx 设置堆的最大空间大小。

java -Xms20m -Xmx30m GCDemo

在上面的命令中,我们设置 JVM 的初始堆大小为 20M,最大堆空间为 30M。

年轻代

在 JDK1.8 中,堆分为年轻代和老年代。JVM 提供了参数 -Xmn 来设置年轻代内存的大小,但没有提供参数设置老年代的大小。但其实老年代的大小就等于堆大小减去年轻代大小。

java -Xms20m -Xmn10M GCDemo

上面的命令中,我们设置 JVM 堆初始大小为20M。其中年轻代的大小为 10M,那么剩下的就是老年代的大小,有 10M了。 我们可以给上述命令加上-XX:+PrintGCDetails 参数来查看内存区域的分配信息。

如上图所示,我们可以看到老年代的大小为 10M。

Eden区

在年轻代中,分为三个区域,分别是:eden 空间、from 空间、to 空间。如果要设置这部分的大小,那么就使用 -XX:SurvivorRatio 这个参数,该参数设置 eden / from 空间的比例关系,该参数的公式如下:

-XX:SurvivorRatio = eden/from = eden/to

例如我们的年轻代有 10 M,而我们设置 -XX:SurvivorRatio 参数为 2。也就是说 eden / from = eden / to = 2。这里教一个快速计算的方法,我们假设 eden = 2,那么 from = 1,to = 1,那么 eden + from + to = 10M。这样就可以算出每一份大小是 10/4 = 2.5M。所以 Eden 区 = 2.5 * 2 = 5M,from 区是 2.5 M,to 区是 2.5 M。

下面我们运行下命令来验证一下。

java -Xms20m -Xmn10M -XX:SurvivorRatio=2 -XX:+PrintGCDetails GCDemo

在上面的启动参数中,我们设置堆初始大小为 20M,年轻代大小为 10M,年轻代的 SurvivorRatio 比例为 2。那么最终分配的结果将会是:年轻代 10M,其中 Eden 区 5M、From 区 2.5M、To 区 2.5 M,老年代 10M。

从上图可以看到:eden 空间是 5120 K,from 和 to 空间是 2560 K。

上图还有一个细节,即 PSYoungGen 这里的 total 只有 7680K,难道年轻代只有 7.5M 的内存吗?为什么不是 10M 呢?其实是因为这里的 total 指的是可用内存,from space 和 to space 两个区域,同一时间只有一个区域是可以用的。所以可用内存是 5120 + 2560 = 7680。

永久代(JDK1.7)

在 JDK 1.8 之前,所加载的类信息都放在永久代中。我们用 -XX:PermSize 设置永久代初始大小,用 -XX:MaxPermSize 设置永久代最大大小。

java -XX:PermSize10m -XX:MaxPermSize50m -XX:+PrintGCDetails GCDemo

在上面的启动参数中,我们设置永久代初始大小为 10M,最大大小为 50M。我们在 JDK1.7 的环境下运行上面的命令,会看到如下的 GC 日志。

在上图中,我们可以看到永久代的大小为我们设置的 10M。

元空间(JDK1.8)

在 JDK 1.8 之前,所有加载的类信息都放在永久代中。但在 JDK1.8 之时,永久代被移除,取而代之的是元空间(Metaspace)。在元空间这块内存中,有两个参数很相似,它们是: -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize。

java -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=50m -XX:+PrintGCDetails GCDemo

上面的命令中,我们设置 MetaspaceSize 为 10M,MaxMetaspaceSize 为 50M。但其实它们并不是设置初始大小和最大大小的。

从上面的执行结果可以看到,Metaspace 空间的大小为 2.6M 左右,并不是我们设置的 10M。那是因为 MetaspaceSize 设置的是元空间发生 GC 的初始阈值。当达到这个值时,元空间发生 GC 操作,这个值默认是 20.8M。而 MaxMetaspaceSize 则是设置元空间的最大大小,默认基本是机器的物理内存大小。虽然可以不设置,但还是建议设置一下,因为如果一直不断膨胀,那么 JVM 进程可能会被 OS kill 掉。

栈空间

栈空间是每个线程各自有的一块区域,如果栈空间太小,也会导致 StackOverFlow 异常。而要设置栈空间大小,只需要使用 -Xss 参数就可以。

java -Xss2m GCDemo

上面的启动命令设置最大栈空间为 2M。

直接内存

在 JVM 中还有一块内存,它独立于 JVM 的堆内存,它就是:直接内存。我们可以使用 -XX:MaxDirectMemorySize 设置最大直接内存。如果不设置,默认为最大堆空间,即 -Xmx。

java -XX:MaxDirectMemorySize=50m GCDemo

上面的启动命令设置直接内存最大值为 50M。

当直接内存使用达到设置值时,就会触发垃圾回收。如果不能有效释放足够空间,就会引发直接内存溢出导致系统的 OOM。

总结

参数 含义
-Xms 初始堆大小
-Xmx 最大堆空间
-Xmn 设置新生代大小
-XX:SurvivorRatio 设置新生代eden空间和from/to空间的比例关系
-XX:PermSize 方法区初始大小
-XX:MaxPermSize 方法区最大大小
-XX:MetaspaceSize 元空间GC阈值(JDK1.8)
-XX:MaxMetaspaceSize 最大元空间大小(JDK1.8)
-Xss 栈大小
-XX:MaxDirectMemorySize 直接内存大小,默认为最大堆空间

参考资料


如果只是看,其实无法真正学会知识的。为了帮助大家更好地学习,我建了一个虚拟机群,专门讨论学习 Java 虚拟机方面的内容,每周针对我所发文章进行讨论答疑。如果你有兴趣,关注「Java技术精选」公众号,通过右下角菜单「入群交流」加我好友,小助手会拉你入群。


JVM系列目录

原文地址:https://www.cnblogs.com/chanshuyi/p/jvm_serial_11_jvm_param_heap_stack.html

JVM基础--JVM参数之堆栈空间配置的更多相关文章

  1. JVM基础系列第11讲:JVM参数之堆栈空间配置

    JVM 中最重要的一部分就是堆空间了,基本上大多数的线上 JVM 问题都是因为堆空间造成的 OutOfMemoryError.因此掌握 JVM 关于堆空间的参数配置对于排查线上问题非常重要. tips ...

  2. JVM基础系列第14讲:JVM参数之GC日志配置

    说到 Java 虚拟机,不得不提的就是 Java 虚拟机的 GC(Garbage Collection)日志.而对于 GC 日志,我们不仅要学会看懂,而且要学会如何设置对应的 GC 日志参数.今天就让 ...

  3. JVM基础系列第13讲:JVM参数之追踪类信息

    我们都知道 JVM 在启动的时候会去加载类信息,那么我们怎么得知他加载了哪些类,又卸载了哪些类呢?我们这一节就来介绍四个 JVM 参数,使用它们我们就可以清晰地知道 JVM 的类加载信息. 为了方便演 ...

  4. JVM基础系列第15讲:JDK性能监控命令

    查看虚拟机进程:jps 命令 jps 命令可以列出所有的 Java 进程.如果 jps 不加任何参数,可以列出 Java 程序的进程 ID 以及 Main 函数短名称,如下所示. $ jps 6540 ...

  5. JVM基础系列第10讲:垃圾回收的几种类型

    我们经常会听到许多垃圾回收的术语,例如:Minor GC.Major GC.Young GC.Old GC.Full GC.Stop-The-World 等.但这些 GC 术语到底指的是什么,它们之间 ...

  6. JVM基础系列第9讲:JVM垃圾回收器

    前面文章中,我们介绍了 Java 虚拟机的内存结构,Java 虚拟机的垃圾回收机制,那么这篇文章我们说说具体执行垃圾回收的垃圾回收器. 总的来说,Java 虚拟机的垃圾回收器可以分为四大类别:串行回收 ...

  7. JVM基础系列第8讲:JVM 垃圾回收机制

    在第 6 讲中我们说到 Java 虚拟机的内存结构,提到了这部分的规范其实是由<Java 虚拟机规范>指定的,每个 Java 虚拟机可能都有不同的实现.其实涉及到 Java 虚拟机的内存, ...

  8. JVM基础系列第7讲:JVM 类加载机制

    当 Java 虚拟机将 Java 源码编译为字节码之后,虚拟机便可以将字节码读取进内存,从而进行解析.运行等整个过程,这个过程我们叫:Java 虚拟机的类加载机制.JVM 虚拟机执行 class 字节 ...

  9. JVM基础系列第6讲:Java 虚拟机内存结构

    看到这里,我相信大家对于一个 Java 源文件是如何变成字节码文件,以及字节码文件的含义已经非常清楚了.那么接下来就是让 Java 虚拟机运行字节码文件,从而得出我们最终想要的结果了.在这个过程中,J ...

随机推荐

  1. JS DOM节点的增删改查

    合并拆分 行内样式  script写在html里面

  2. API管理的五大规则

    http://www.csdn.net/article/2012-12-18/2812929-5-Rules-For-API-Management 1. 设计 开发人员使用API访问各种不同的类,并且 ...

  3. iOS9新系统下App Store应用上传新指南

    http://www.cocoachina.com/appstore/20151010/13691.html 最近频繁收到小伙伴们的反馈,说经过前期学习已对ASO规则略有了解,但APP的提交审核是由技 ...

  4. 学习iOS设计--iOS8的颜色、文字和布局学习

    在去年,Apple针对新时代用户彻底更新了其设计语言.现在的设计语言相对之前大为简化,能够让设计师将精力集中到动画和功能上,而不是繁复的视觉细节上. 很多人都曾问过我:设计应当如何入门?成为一名优秀设 ...

  5. 2019-4-29-dotnet-core-通过-frp-发布自己的网站

    title author date CreateTime categories dotnet core 通过 frp 发布自己的网站 lindexi 2019-04-29 12:26:45 +0800 ...

  6. Kubernetes1.4正式发布

    Kubernetes1.4正式发布. 昨天刚预测1.4即将正式发布,结果晚上Kubernetes1.4就正式发布了. 先看看Kubernetes发布历史: Kubernetes 1.0 - 2015年 ...

  7. hdu4318 最短路变形

    和hdu有一题差不多.给的是损失比,1-c%就是保存了多少,找出最大的保存率即可. #include<stdio.h> #include<iostream> #include& ...

  8. spring-data-jpa实体类继承抽象类如何映射父类的属性到数据库

    在抽象父类上加上注解@MappedSuperclass @MappedSuperclass public class Pet { private Integer id;//id private Str ...

  9. 洛谷4137 mex题解 主席树

    题目链接 虽然可以用离线算法水过去,但如果强制在线不就gg了. 所以要用在线算法. 首先,所有大于n的数其实可以忽略,因为mex的值不可能大于n 我们来设想一下,假设已经求出了从0到n中所有数在原序列 ...

  10. @codeforces - 718E@ Matvey's Birthday

    目录 @description@ @solution@ @accepted code@ @detail@ @description@ 给定一个长度为 n 的字符串 s,保证只包含前 8 个小写字母 ' ...