JVM内存区域

elltor 2021年05月02日 48次浏览

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

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

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

JVM内存区域划分

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

image.png

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

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

  • 堆:heap,这是Java主要存放对象数据的地方,它是一块共享的数据区域,多个线程可以访问,同时堆也是GC主要管理的区域。
    • 在Hotspot虚拟机中,堆被划分成了年轻代(young generation)和老年代(old generation),如下图:
    • image.png
  • 方法区:方法区用来存放类信息、常量、静态变量,常量池也在方法区
  • 虚拟机栈: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虚拟机就是使用直接对象访问的方式。