Java内存学习-int类型

Java内存学习-int类型

使用openjdk中jol-java object layout工具,可以输出对象在内存中分布情况,了解内存结构、消耗及访问机制

以下文章以Int类型为例

1.图例

 

Java内存学习-int类型

64 bit jvm with pointer compression

Java内存学习-int类型

64bit jvm

Java内存学习-int类型

32bit jvm

Java内存学习-int类型

Java内存学习-int类型

2.不同参数对比

对比三个输出,

如果VM小于64G, object header大小 12 bytes= 8 (mark word) + 4 (class word)

如果VM大于64G, object header大小 16 bytes= 8 (mark word) + 8 (class word)

如果VM关闭指针压缩, object header大小 16 bytes= 8 (mark word) + 8 (class word)

2.1.开启指针压缩后JOL输出

# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

java.lang.Integer object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)  # Mark word
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)  # Mark word
      8     4        (object header)                           be 22 00 20 (10111110 00100010 00000000 00100000) (536879806)# Class word
     12     4    int Integer.value                             1
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

[email protected] object externals:
          ADDRESS       SIZE TYPE              PATH                           VALUE
        6b0fd3480         16 java.lang.Integer                                1

size : 16

 

2.2.最大堆设置超过64g后的JOL输出

# Field sizes by type: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

java.lang.Integer object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1) # Mark word
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0) # Mark word
      8     4        (object header)                           c8 30 32 28 (11001000 00110000 00110010 00101000) (674377928)# Class word
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)# Class word
     16     4    int Integer.value                             1
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

[email protected] object externals:
          ADDRESS       SIZE TYPE              PATH                           VALUE
        b2ab94b48         24 java.lang.Integer                                1

size : 24

 

 

2.3.关闭指针压缩的JOL输出

# Running 64-bit HotSpot VM.
# Objects are 8 bytes aligned.
# Field sizes by type: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

java.lang.Integer object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)   # Mark word
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)   # Mark word
      8     4        (object header)                           c8 30 cd 16 (11001000 00110000 11001101 00010110) (382546120) # Class word
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)# Class word
     16     4    int Integer.value                             1
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

[email protected] object externals:
          ADDRESS       SIZE TYPE              PATH                           VALUE
         d3e14b48         24 java.lang.Integer                                1


size : 24

 

 

2.4.关于对象指针压缩

OOP = “ordinary object pointer” 普通对象指针。

通常64位JVM消耗的内存会比32位的大1.5倍,这是因为对象指针在64位架构下,长度会翻倍(更宽的寻址)。对于那些将要从32位平台移植到64位的应用来说(假如编译和运行环境同为32或同为64不需要手动开启),内存占用会增多,不太合理。从JDK 1.6 update14开始,64 bit JVM正式支持了 -XX:+UseCompressedOops 这个可以压缩指针,起到节约内存占用的新参数。

启用CompressOops后,会压缩的对象:
• 每个Class的属性指针(静态成员变量)
• 每个对象的属性指针
• 普通对象数组的每个元素指针

压缩也有局限性,针对一些特殊类型的指针,JVM是不会优化的。比如指向PermGen的Class对象指针,本地变量,堆栈元素,入参,返回值,NULL指针不会被压缩。

机制是解释器在解释字节码时,植入压缩指令(不影响正常和JVM优化后的指令顺序)。当对象被读取时,解压,存入heap时,压缩。

关于大小:

    32位系统,占用 8 字节。Mark Word占用4个字节,Klass Pointer占用4个字节,数组长度占用4个字节。实际数据:引用类型占用4个字节。
    64位系统,开启UseCompressedOops压缩时,占用 12 字节。Mark Word占用8个字节,Klass Pointer占用4个字节,数组长度占用4个字节。实际数据:引用类型占用4个字节。

    64位系统,关闭UseCompressedOops压缩或者最大堆64G时,占用16字节。 Mark Word占用8个字节,Klass Pointer占用8个字节,数组长度占用4个字节。实际数据:引用类型占用8个字节。

 

3.JOL使用方法

3.1.方法一:启动java应用时加载jol,及指定参数
指定classpath及jar参数,查看自己的类布局
java -jar jol-cli-0.3.2-full.jar internals -cp demoapp.jar com.zc.test.jol.TO1

指定classpath参数,查看自己的类布局
java -cp demoapp.jar;jol-cli-0.3.2-full.jar org.openjdk.jol.Main internals com.zc.test.jol.TO1

 

3.2.方法二:代码加载jol,查看自己的对象或类布局

如下代码样例
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.info.GraphLayout;
import org.openjdk.jol.vm.VM;


//-XX:+UseCompressedOops 与 -XX:-UseCompressedOops
public class CompressOops1 {
    public static void main(String[] args) {
        int i = 1;
        
        System.out.println(VM.current().details());
        //查看对象内部信息
        System.out.println(ClassLayout.parseInstance(i).toPrintable());
        //查看对象外部信息
        System.out.println(GraphLayout.parseInstance(i).toPrintable());
        //获取对象总大小
        System.out.println("size : " + GraphLayout.parseInstance(i).totalSize());
        
        
    }
}

 

3.3.JOL常用的三个函数方法

  • ClassLayout.parseInstance(object).toPrintable():查看对象内部信息

  • GraphLayout.parseInstance(object).toPrintable():查看对象外部信息,包括引用的对象

  • GraphLayout.parseInstance(object).totalSize():查看对象总大小

 

3.4.JOL输出信息介绍

输出4, 1, 1, 2, 2, 4, 4, 8, 8 分别表示:引用句柄, byte, boolean, char, short, int, float, double, long长度

输出# Using compressed oop with 3-bit shift. # Using compressed klass with 3-bit shift.表示启用指针压缩

 

3.4.输出信息中对象组成

对象头

普通对象:

    Mark Word:包含HashCode、分代年龄、锁标志等。

    Klass Pointer:指向当前对象的Class对象的内存地址。

数组对象:

    Mark Word:包含HashCode、分代年龄、锁标志等。

    Klass Pointer:指向当前对象的Class对象的内存地址。

    Length:数组长度

 

 

4.参考

Java Objects Inside Out-https://shipilev.net/jvm/objects-inside-out/

Java Memory Management - https://training.xceptance.com/java/410-memory-management.html