JVM堆内存相关的启动参数:年轻代、老年代和永久代的内存分配
如果想观察JVM进程占用的堆内存,可以通过命令工具jmap或者可视化工具jvisualvm.exe。JVM这些启动参数都拥有默认值,如果想了解JVM的内存分配策略,最好手动设置这些启动参数。再通过JDK提供的工具的统计结果,进行对比,就比较容易理解这些内存分配的理论知识。运行环境是win7 32位操作系统,JDK1.7.0_60版本。
测试代码和JVM启动参数如下:
public class Test
{
public static void main(String[] args)
{
int a = 0;
while (true)
{
a++;
}
}
}
-Xms=200M -Xmx200M -XX:NewSize=100M -Xmn100M -XX:SurvivorRatio=8
-XX:OldSize=60M -XX:PermSize=50M -XX:MaxPermSize=50M
运行上述代码,通过jps命令获取到进程pid,然后通过jmap -heap pid就可以查看内存分配和使用情况。
>jmap -heap 8912
Attaching to process ID 8912, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 24.60-b09
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 209715200 (200.0MB)
NewSize = 104857600 (100.0MB)
MaxNewSize = 104857600 (100.0MB)
OldSize = 62914560 (60.0MB)
NewRatio = 3
SurvivorRatio = 8
PermSize = 52428800 (50.0MB)
MaxPermSize = 52428800 (50.0MB)
这里显示的堆配置参数,都可以通过JVM启动参数来设置。下面来解释下几个重要参数的含义:
-Xms 和 -Xmx (-XX:InitialHeapSize 和 -XX:MaxHeapSize):指定JVM初始占用的堆内存和最大堆内存。JVM也是一个软件,也必须要获取本机的物理内
存,然后JVM会负责管理向操作系统申请到的内存资源。JVM启动的时候会向操作系统申请 -Xms 设置的内存,JVM启动后运行一段时间,如果发现内存空间
不足,会再次向操作系统申请内存。JVM能够获取到的最大堆内存是-Xmx设置的值。
-XX:NewSize 和 -Xmn(-XX:MaxNewSize):指定JVM启动时分配的新生代内存和新生代最大内存。
-XX:SurvivorRatio:设置新生代中1个Eden区与1个Survivor区的大小比值。在hotspot虚拟机中,新生代 = 1个Eden + 2个Survivor。如果新生代内存是
10M,SurvivorRatio=8,那么Eden区占8M,2个Survivor区各占1M。
-XX:NewRatio:指定老年代/新生代的堆内存比例。在hotspot虚拟机中,堆内存 = 新生代 + 老年代。如果-XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆内存的1/5。在设置了-XX:MaxNewSize的情况下,-XX:NewRatio的值会被忽略,老年代的内存=堆内存 - 新生代内存。老年代的最大内存 = 堆内存 - 新生代 最大内存。
-XX:OldSize:设置JVM启动分配的老年代内存大小,类似于新生代内存的初始大小-XX:NewSize。
-XX:PermSize 和 -XX:MaxPermSize:指定JVM中的永久代(方法区)的大小。可以看到:永久代不属于堆内存,堆内存只包含新生代和老年代。
可以发现:堆内存、新生代内存、老年代内存、永久代内存,都有一个初始内存,还有一个最大内存。下面以老年代的初始内存和最大内存为例,看下内存变化的效果,其他的应该类似。测试代码如下:
public class TurnedTest
{
private static List<string> list = new ArrayList<string>();
public static void main(String[] args)
{
int a = 0;
while (true)
{
a++;
list.add("demo");
}
}
}
显然这个程序存在内存泄露,最终会占满整个堆内存,抛出OOM。为了看清楚这个演变的过程,我们在while循环中添加一个断点,设置breakpoint properties中的"hit count"为100000,以debug模式运行上面的程序,然后使用jmap观察内存占用情况。
tenured generation:
capacity = 62914560 (60.0MB)
used = 0 (0.0MB)
free = 62914560 (60.0MB)
0.0% used
tenured generation:
capacity = 62914560 (60.0MB)
used = 16409080 (15.648918151855469MB)
free = 46505480 (44.35108184814453MB)
26.08153025309245% used
tenured generation:
capacity = 62914560 (60.0MB)
used = 53329496 (50.858970642089844MB)
free = 9585064 (9.141029357910156MB)
84.76495107014973% used
tenured generation:
capacity = 104857600 (100.0MB)
used = 84217880 (80.3164291381836MB)
free = 20639720 (19.683570861816406MB)
80.3164291381836% used
可以发现老年代内存从最开始的60M,扩大到最大值100M。
相关文章
- 华为技术专家居然把JVM内存模型讲解这么细致
- 【JVM笔记】GC算法详解
- JVM监控:JMX组件与底层原理
- JVM内存简单理解
- JAVA JVM 流程一
- [转]JVM参数设置、分析
- 第四章 JVM垃圾回收算法
- 第一章 JVM内存结构
- 面试官问我JVM内存结构,我真的是
- Java 虚拟机JVM运行参数优化相关
- Tomcat 内存溢出 "OutOfMemoryError" 问题总结 (JVM参数说明)
- JVM 堆外内存查看方法
- jvm 堆内存 栈内存 大小设置
- Tomcat和JVM的性能调优总结
- JVM性能调优实践——JVM篇
- 设置 Tomcat 的JVM运行内存
- JVM内存模型,以及JVM性能调优
- 【JVM】Java8 和 Java7中JVM内存模型有什么区别
- 程序 查看 jvm版本
- jstat查看jvm的GC
- 主要的JVM的分类
- tomcat 配置jvm参数
- JVM之关于GC的扩展知识
- java-jvm-内存分区
- 记录一次索引未建立、继而引发一系列的问题、包含索引创建失败、虚拟机中JVM虚拟机内存满的情况
- 大数据Spark “蘑菇云”行动第94课:Hive性能调优之Mapper和Reducer设置、队列设置和并行执行、JVM重用和动态分区、Join调优
- 从原理聊JVM(三):详解现代垃圾回收器Shenandoah和ZGC | 京东云技术团队
- 谈一谈JVM内存JAVA_OPTS参数
- java jvm 参数 -Xms -Xmx -Xmn -Xss 调优总结
- 关于jvm系统属性-Djava.awt.headless 模式
- JVM内存—堆(heap)栈(stack)方法区(method) (转)
- JVM系列 实用命令(jmap、jstat、jstack)
- 【jvm我能讲两小时006】什么是聚集索引?
- 【jvm我能讲两小时067】老年代存放的都是什么对象?