JVM是如何进行内存区域划分的?

JVM内存布局

JVM内存区域划分

  • 堆中的数据是共享的,占内存中最大的一块
  • 执行字节码的模块叫执行引擎
  • 执行引擎线程切换依靠的是程序计数器
  • JAVA虚拟机栈、本地方法栈维度是属于线程的
  • 本地内存包含元数据区和一些直接内存

虚拟机栈


栈里的每条数据,就是栈帧。每个方法被调用时,都会创建一个栈帧,并入栈。完成相关调用就出栈。所有栈帧都出栈,则线程结束。

栈帧包含四个区域

  • 局部变量表
  • 操作数栈
  • 动态链接
  • 返回地址

本地方法栈和虚拟机栈很相似,但是它服务的是native方法。


特殊的数据类型--returnAdress

这是一个只存在于字节码层面的类型。程序就是存储在方法区的字节码指令,而returnAddress类型的值就是指向特定指令内存地址的指针

  • 两层栈,第一层是栈帧,对应着方法,第二层是方法的执行,对应的操作数
  • 所有的字节码指令,其实都会抽象成入栈、出栈操作

程序计数器

程序技术器是一块较小的内存空间,可看做是当前线程所执行的字节码的行号指示器。

字节码

上图中红框是偏移地址,可认为是计数器内容。


堆是内存中最大的区域,垃圾回收针对的就是堆。程序启动时,堆就申请了。

堆不仅要进行垃圾回收,还要进行空间整理。因为长时间运行后,堆空间有很多细小碎片

Java对象可以分为基本数据类型和普通对象。

对于普通对象,JVM首先在堆上创建对象,然后在其他地方使用的其实是它的引用。比如这个引用保存在虚拟机栈的局表变量表中。
对于基本数据类型,分两个情况:
1、前面说到每个线程都有自己的虚拟机栈,在方法体内声明的基本类型直接在栈上分配。
2、像int[]这样的数组,它是在堆上分配的。数组不是基本的数据类型。

堆是线程共享的,如果多个线程同时访问,会涉及同步问题,这里留作后续说明。

元空间

思考类和对象的区别:类是活生生的个体,参与运行;类更像是一个模板。

Java8之前,这些类信息放在Perm区,但是这个区域大小有限,容易造成溢出

元空间可以使用操作系统的空间,不会出现溢出,但是无限制使用会导致操作系统死亡。一般使用参数-XX:MaxMetaspaceSize控制大小

方法区

作为一个概念,仍然存在。它的物理存储的容器就是Metaspace。这个区域存储的内容包括:类的信息、常量池、方法数据、方法代码。

总结

  • 字符串常量池(注意不是常量池)存在堆中
  • 堆、非堆、本地内存关系如下图:
Last modification:March 29th, 2020 at 08:25 pm