在 Java 虚拟机(JVM)中,对象的存储主要涉及几个关键部分:堆内存、方法区以及栈内存。以下是关于 Java 对象在 JVM 中如何存储的详细说明:
堆(Heap)
- 对象实例数据:几乎所有的对象实例数据都存储在堆上。堆是线程共享的内存区域,用于存放对象实例和数组。Java 程序计数器会指向这个区域来访问对象。
- 垃圾回收:堆是垃圾收集器管理的主要区域,根据垃圾回收机制的不同,堆可能被划分为新生代(Eden空间、From Survivor空间、To Survivor空间)和老年代等。
方法区(Method Area)
- 类信息:虽然不是直接存储对象的地方,但方法区存储了每个已加载类的结构信息,包括运行时常量池、字段和方法数据、构造函数和普通方法的字节码内容等。这些信息对于创建对象实例至关重要。
栈(Stack)
- 引用:当一个对象被创建时,其引用(即对象的地址)通常存储在虚拟机栈的局部变量表中。每个方法执行时都会创建一个栈帧,其中包含了局部变量表、操作数栈、动态链接、方法出口等信息。局部变量表存放了编译期可知的各种基本数据类型、对象引用(reference类型,不等同于对象本身)和
returnAddress
类型(指向了一条字节码指令的地址)。
运行时常量池
- 它是方法区的一部分,用于存储编译期间生成的各种字面量和符号引用,这部分内容会在类加载后进入方法区的运行时常量池中。
对象头(Object Header)
- 每个对象都有一个对象头,它包含了一些元数据信息,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。如果是数组,对象头还会有一个额外的部分记录数组长度。
实例数据(Instance Data)
- 这是对象真正存储的有效信息,即我们在程序代码里面所定义的各种字段的内容,包括父类中继承下来的和子类中定义的字段。
对齐填充(Padding)
- 并非必然存在,也没有特别的含义,仅仅起占位作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是对象的大小必须是8字节的整数倍。因此,如果对象的实际数据大小不是8字节的整数倍,则需要通过对齐填充来补全。
综上所述,当你在 Java 中创建一个对象时,该对象的具体数据会被分配到堆内存中,而对该对象的引用则存放在栈内存里。同时,与该对象相关的类信息则保存在方法区内。
这样的设计保证了 Java 应用程序能够高效地管理和使用内存资源。
THE END