内存模型

177 阅读2分钟

jvm内存区域

运行时数据区域

程序计数器

  • 程序计数器是属于线程私有的
  • 记录了当前线程切换前程序所处于的位置,方便线程切换回来后,能恢复的正确的执行位置
  • 如果运行的是Java方法,则记录的是虚拟机字节码指令的地址,如果是本地方法,这个计数器为空

Java虚拟机栈

  • java虚拟机栈也是线程私有的
  • 在每个方法运行时都会创建一个栈帧,记录局部变量表,操作数栈,动态链接等信息
  • 当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,方法运行期间是不会改变局部变量表的

局部变量表

  • 存放了编译器可知的基本数据类型,对象引用,returnAddress类型

本地方法栈

  • 与虚拟机栈相似,只不过为本地方法服务

Java堆

  • Java堆是线程公有的
  • 此内存区域的唯一目的就是存放对象实例,几乎所有的实例都在堆中分配。
  • 有一部分内存实在栈上分配的(通过逃逸分析)
  • java堆是垃圾回收管理的主要区域

逃逸分析

  • 方法逃逸

当一个对象在方法中定义之后,作为参数传递到其它方法中

  • 线程逃逸

如类变量或实例变量,可能被其它线程访问到

优化

如果不存在逃逸行为,则可以对该对象进行如下优化
  • 同步消除

线程同步本身比较耗时,如果逃逸分析确定不会掏出线程,则消除同步,开启同步消除需要先开启逃逸分析典型例子stringBuffer.append("");

  • 标量替换
  1. 标量是指不可分割的量,如java中基本数据类型和reference类型,相对的一个数据可以继续分解,称为聚合量
  2. 如果把一个对象拆散,将其成员变量恢复到基本类型来访问就叫做标量替换
  3. 如果逃逸分析发现一个对象不会被外部访问,并且该对象可以被拆散,那么经过优化之后,并不直接生成该对象,而是在栈上创建若干个成员变量
  • 栈上分配

在栈上分配对象

方法区

  • 是线程共享区域
  • 通常加载类信息,常量,静态变量,即时编译后的代码等
  • 这里需要知道永久代与方法区不对等,只是Hotspot使用永久代来实现方法区,其他虚拟机并不是

运行时常量池

  • 是方法区的一部分
  • 常量池(用于存放编译器生产的各种字面量和符号引用)