一、如何诊断和监控JVM堆内核堆外内存使用

  • 可以使用综合性的图形化工具,如JConsole
  • 可以使用命令行工具进行运行时查询,如 jstat 和 jmap ,可以查看堆,方法区等使用数据。
  • 可以使用jmap等提供的命令,生成堆转储(Heap Dump)文件,然后利用 jhat 等堆转储分析工具进行详细分析

二、堆内部结构

对于堆内存,最常见的是新生代和老生代的划分。随着JVM的发展和新的GC方式的引入,进行了一些细分。

查看当前java进程的堆内存使用情况详解 java查看堆外内存使用情况_Java

按照通常的GC年代方式划分,Java堆内分为新生代和老生代。

1.新生代

新生代是大部分对象创建和销毁的区域。在常见的Java应用中,绝大部分对象生命周期是很短暂的,朝生夕死。新生代内部又分为Eden区域和两个Survivor区域。Eden区作为对象初始分配的区域,两个Survivor,有时候也叫做from、to区,被用来放置从Minor GC中保留下来的对象。

JVM会随便选取一个Survivor区域作为“to”,然后会在GC过程中进行区域间拷贝,也就是将Eden中存活下来的对象和from区域的对象,拷贝到这个“to”区域。这种设计主要是为了防止内存的碎片化,并进一步清理无用对象。

2.老年代

放置长生命周期的对象,通常都是从Survivor区域拷贝过来的对象。当然也有特殊情况,我们知道普通的对象会被分配在TLAB上;如果对象较大,JVM会试图直接分配在Eden其他位置上;如果对象太大,完全无法在新生代找到足够长的连续空闲空间,JVM就会直接分配到老年代。

3.永久代

这部分在早期Hotspot JVM的方法区,存储Java类元数据、常量池、Intern字符串缓存。在JDK8之后就不存在永久代了。


三、JVM参数

  • 最大堆体积
-Xmx value
  • 初始的最小堆体积
-Xms value
  • 老年代和新生代的比例
-XX:NewRatio=value

 默认情况下,这个数值是2,意味着老年代时新生代的2倍大。

  • Eden和Survivor的大小比例
-XX:SurvivorRatio=value