JVM 内存区域介绍

Java 相较于 C++具有内存自动管理功能,内存管理是个宽泛的概念,它即指实例化对象是的内存分配又指 GC 回收无用的类、对象、变量等。随着 JVM 不断发展,JVM 内存区也在不断变化,这些变化在 Java 语言层面感知不到,因为字节码屏蔽了底层实现,了解 JVM 内存区域是深入学习 Java 的第一步,今天总结一下。

JVM 是《Java 虚拟机规范》的实现

《Java 虚拟机规范》定义了 Java 字节码规范及实现 Java 的注意事项,而 JVM 是它的具体实现,它们是一对多的关系,很多公司(Sun、IBM、Redhat、甲骨文)都对它有具体的实现。刚刚提到“随着 Java 语言的发展 Java 内存区域不断变化”这句话是不太严谨的,其实在不同的 JVM 上在内存管理、内存区域划分都是存在差异的,每个都有其特点。

JVM 内存区域划分

一般我们把内存区域划分为如下几个,如下图:

从上图我们可以清晰的看到堆、方法区、直接内存(又称堆外内存)都是共享的,共享的意思是可以被多个线程访问和使用,而虚拟机栈、本地方法栈、程序计数器是线程私有的,而且每个线程都有自己的一份。

下面介绍各个区域的作用及存放的数据。

  • 堆:heap,这是 Java 主要存放对象数据的地方,它是一块共享的数据区域,多个线程可以访问,同时堆也是 GC 主要管理的区域。
    • 在 Hotspot 虚拟机中,堆被划分成了年轻代(young generation)和老年代(old generation),如下图:
  • 方法区:方法区用来存放类信息、常量、静态变量,常量池也在方法区
  • 虚拟机栈:Java Vertical Machine Stack,虚拟机栈中用来存放方法的入栈信息,每个入栈的方法称为栈帧(Stack Frame),栈帧记录的方法的信息,局部变量表,返回值信息。其中局部变量表存储的主要为基本数据类型(char、short、int、long、float、double)和引用(reference)。在 JDK7+移除了方法区,改为了元数据(Meta Data)
  • 本地方法栈:Native Method Stack,本地方法栈存储调用操作系统的方法,这些方法由 C/C++实现,调用时要通过 JVM 调用。在 HotSpot 虚拟机中虚拟机栈和本地方法栈和并到了一起。
  • 程序计数器,用户 JVM 执行字节码时记录程序执行位置
  • 直接内存:direct menory,直接内存不属于运行时数据区,但它被 JVM 所管理,在 Java 中通过 nio 的 DirectByteBuffer 创建对象就作为了这块直接内存的管理对象

对象的内存布局

对象的组成部分。

image.png

  • 对象头:header/ mark word,这是记录对象 hash 码,分代年龄,锁标志灯信息的地方,数据长度为 32 位或 64 位,如果 JVM 开启头部压缩就是 32 为。
  • 数据区用来存在对象数据
  • 对齐:一个对象必须为 8 字节的整数倍,如果不足填错空字节补齐。

对象的访问

image.png

image.png

对比&区别:

  • 基于句柄的对象访问,需要先访问一次句柄才能访问到对象,但是句柄确保了引用指定不为 null,因此引用的状态比较稳定。其确点是访问比较慢。
  • 直接访问方式,是引用直接指向对象,如果未初始化,应用指向为 null,其优点是访问比较快,Hotspot 虚拟机就是使用直接对象访问的方式。

(本文完)