Java 对象内存布局

本文来自:http://www.ibm.com/developerworks/cn/java/j-codetoheap/

寻址能力与用户空间

进程能够处理的位数取决于处理器能寻址的内存范围,处理器的寻址能力取决于处理器的位数,比如 32 位能寻址 2^32,也就是 4G。

处理器提供的部分可寻址范围由 OS 本身用,供操作系统内核以及 C 运行时。OS 和 C 运行时占用的内存数量取决于所用的 OS,比如 Windows 默认占用 2GB。剩余的可寻址空间是供运行的实际进程使用的内存(用户空间)。

对于 Java 应用程序,用户空间是 Java 进程占用的内存,实际上包含两个池:Java 堆和本机(非 Java)堆。Java 堆的大小由 JVM 的 Java 堆设置控制:-Xms 和 -Xmx 分别设置最小和最大 Java 堆。在按照最大的大小设置分配了 Java 堆之后,剩下的用户空间就是本机堆。
32bit JVM

可寻址范围总共有 4GB,OS 和 C 运行时大约占用了其中的 1GB,Java 堆占用了将近 2GB,本机堆占用了其他部分。请注意,JVM 本身也要占用内存,就像 OS 内核和 C 运行时一样,而 JVM 占用的内存是本机堆的子集。

Java 对象内存布局

JVM 需要额外的开销来描述 Java 对象的元数据。

对象元数据一般包括:

  • 类型指针:占用一个CPU字。一个指向类信息的指针,描述了对象的类型。
  • 标记:占用一个CPU字。一组标记,描述了对象的状态,包括对象散列码(如果有)以及对象的形状(是否是数组)。
  • 锁:占用一个CPU字。对象的同步信息,对象目前是否正在同步。(每个对象都有一个内置锁)
  • Size数组长度:如果标记显示这个对象是数组,描述了数组的长度。(虽然 Java 语言里数组的长度是 32位的,但在 64 位的 JVM 里,这个字段还是占用64位,除非开启指针压缩。)

上述元数据中,类型指针、标记、锁 占用的大小取决于 CPU 位宽:32/64 位。

一个 32 位 Java 进程的 int 数组对象的布局示例:
32bit-JVM-int-array-layout

一个 32 位 Java 进程的 java.lang.String 对象的布局示例:
32bit-JVM-String-layout

对于一个 8 个字符的字符串(128 位的 char 数据),需要有 256 位的数据用于字符数组,224 位的数据用于管理该数组的 java.lang.String 对象,因此为了表示 128 位(16 个字节)的数据,总共需要占用 480 位(60 字节)。开销


欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。

Java 对象内存布局》有一个想法

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据