原文是免费电子书,链接:http://www.javacodegeeks.com/whitepaper/jvm-troubleshooting-guide
以下为本人翻译,仅用于交流学习,版权归原作者所有,转载注明出处,请不要用于商业用途 。
这个部分将向你介绍Oracle Java HotSpot虚拟机里不同的Java堆内存空间概览。理解这个对于任何一个涉及到线上经常出现的内存问题的解决非常重要。而具有合适的Java 虚拟机堆空间的知识是很关键的。
Java虚拟机是你Java程序的基础,它提供了动态内存管理服务,垃圾收集,线程,IO以及本地操作等等。
Java堆空间是运行时Java程序的内存“容器”,它为你的Java程序提供了它需要的(Java堆,本地堆)合适的内存空间,并由JVM自身管理。
JVM HotSpot内存被分为3个内存空间:
• The Java Heap(堆)
• The PermGen (持久代)
• 本地堆(C-堆)
下面是他们的详细分类:
内存空间 | 启动参数和调整方法 | 监控方式 | 描述 |
---|---|---|---|
Java 堆 | -Xmx (最大堆容量) -Xms (最小堆容量) EX: -Xmx1024m -Xms1024m |
-verbose GC - JMX API - JConsole - 其他监控工具 |
Java堆是存储你的主要 的Java程序Class实例。 |
持久代 | -XX:MaxPermSize (最大容量) -XX:PermSize (最小容量) EX: -XX:MaxPermSize=512m -XX:PermSize=256m |
- verbose GC - JMX API - JConsole - 其他监控工具 |
Java HotSpot虚拟机持久代空间 是一种JVM存储,主要用于存储 Class对象,如类名 ,类方法, 内部JVM对象和其他JIT优化 相关的数据。 |
本地堆(C-堆) | 不支持直接配置。 对于32位的虚拟机, C堆容量= 4 Gig –堆 – 持久代 对于64位的虚拟机,C堆容量= 服务器总物理内存 &虚拟内存-堆-持久代 |
- 在Windows 和Linux上检查 整个进程大小 - Solaris 和Linux 下用pmap命令行 - AIX上用svmon命令 |
C堆保存各种对象如MMAP文件, 其他JVM和第三方本地代码对象。 |
Java堆空间 – 概览 & 生命周期
你的Java程序生命周期通常看起来像这样:
• Java 程序编码(via Eclipse IDE etc.) ,例如 HelloWorld.java
• Java 程序编译 (Java 编译器或者第三方编译工具如Apache Ant, Apache Maven..),例如 HelloWord.class
• Java 程序启动和运行,例如通过HelloWorld.main() 方法运行。
现在我们来分析你的HelloWorld.class 程序,这样你能更好理解。
• 启动时,JVM会加载并把一些你的静态程序以及JDK库缓存到本地堆里面,包括本地库,映射文件比如你的程序Jar文件,线程比如你的程序的主启动线程等。
• JVM此时会保存你的HelloWorld.class的“静态”数据到持久代空间(Class元数据,描述信息等)
• 一旦你的程序启动,JVM开始管理,并在Java堆里为程序动态的分配内存(年轻代和老年代),这也是为什么了解你的程序需要多大内存空间是如此重要,你可以通过-Xms & -Xmx 的JVM参数恰当的调整你的Java堆大小。通过性能分析,堆转储分析允许你来决定程序的内存占用。
• 最终,当你的程序不再需要内存时,JVM也会动态的从堆里释放内存,这叫垃圾收集。这个过程通过JVM verbose GC或者一个监控工具比如Jconsole能很容易的监控到。
Java HotSpot虚拟机持久代是JVM用来存储你的Java程序Class对象。Java堆主要用来保存实际的短期或者长期的持久代Class对象实例。
持久代本身是完全静态的,除非用第三方工具或者动态类加载中经常用到的Java反射API。
有一点很重要需要注意,这种内存存储方式只应用在Java Hotspot虚拟机上,其他的JVM比如IBM 和Oracle JRockit是没有这种固定以及可配置的持久代存储,它是用其他技术去管理非堆内存(本地内存)。
找到下面一张图,它描述了JVM HotSpot Java堆 vs 持久代 并分析他们各自关联的的属性和容量参数调整。
除了Oracle HotSpot JVM,还有其他各种供应商提供的虚拟机。接下来的部分我们将分析其他JVM的内存配置。理解HotSpot和其他虚拟机在实现和命名约定的不同也很重要。
IBM 虚拟机 内存分为2个区域:
• Java堆 Heap (年轻空间和年老空间)
• 本地堆(C-Heap)
这是他们的分析:
内存空间 | 启动参数和调整方法 | 监控方式 | 描述 |
---|---|---|---|
Java 堆 | -Xmx (最大堆容量) -Xms (最小堆容量) - verbose GC - JMX API - IBM 监控工具 EX: -Xmx1024m -Xms1024m GC 策略Ex: -Xgcpolicy:gencon (使gencon GC 策略生效) |
-verbose GC - JMX API - IBM监控工具 |
IBM Java 堆通常分为年轻代和 年老代(YoungGen, OldGen). 年轻代 GC 策略 (联合了并发和分代GC) 通常用于Java EE 平台,为了最小化 GC暂停时间。 |
本地堆 (C堆) | 不支持直接配置 对于32位虚拟机,C堆容量 = 4 Gig – Java堆 对于64位虚拟机,C堆容量 = 物理服务器总内存 & 虚拟内存 – Java堆 |
- svmon 命令 | C堆用来保存class元数据 对象,包括库文件,其他 JVM以及第三方本地代码对象。 |
也许你也注意到,IBM的虚拟机是没有持久代的。持久代仅用于HotSpot虚拟机。IBM虚拟机是用本地堆保存相关数据的Class元数据。
Oracle也开始打算将持久代从HotSpot里去掉,我们在接下来的部分会讨论。
JRockit 虚拟机内存分为2个部分:
• Java堆(年轻代和老年代)
• 本地内存空间(Class池,C堆,线程…)
内存空间 | 启动参数和调整方法 | 监控方式 | 描述 |
---|---|---|---|
Java 堆 | -Xmx (最大堆容量) -Xms (最小堆容量) EX: -Xmx1024m -Xms1024m |
-verbose GC - JMX API - JRockit Mission Control 工具集 |
JRockit Java堆通常分为年轻代 (短寿命对象)和年老代(长生命周期对象)。 |
本地内存空间 | 不支持直接配置。 对32位虚拟机,本地内存空间容量 = 2-4 Gig – Java堆 ** 依据你操作系统的不同,进程 大小限制 2 GB, 3 GB 或 4 GB ** 对64位虚拟机,本地内存空间容量 = 物理机总内存 &虚拟内存– Java堆 |
- 在Windows和Linux上 检查总进程大小 - Solaris & Linux 的 pmap 命令行 - JRockit JRCMD 工具 |
JRockit本地内存空间用 于存储Class元数据,线程 以及各种对象如库文件, 其他JVM和第三方本地代码对象。 |
和IBM虚拟机类似,JRockit也没有持久代,它使用本地堆存储相关对的Class元数据。
JRockit倾向于用更多的本地内存达到更好的性能。它没有解释模式,只有编译模式,由于它多了本地内存,和同等大小的Sun JVM相比,进程需要的大小通常会大好几百M 。但这不是一个大问题,除非你使用32位的JRockit并加上很大堆空间。这种方式下,对于JRockit(对于32位虚拟机来说,堆越大留个本地堆的就越小)来说,OutOfMemoryError的危险性归咎于本地堆消耗过高 。
HotSpot和JRockit的提供商Oracle的策略,是将这2个虚拟机合成一个,并且包含2个的优点和特性。这也使得JVM调优变得简单,因为未能理解这2个虚拟机的不同会导致错误的调优建议和性能问题。