内存模型
内存模型
Runtime Data Aera
Method Area:
是Java虚拟机规范中的概念,在HotSpot的实现中:
JDK7及以前,HotSpot用永久带来实现方法区,存在jvm内存中,与堆连续的地址空间,GC和老年代一起。
JDK8及以后,HotSpot把很多东西放到了堆或者本地内存,而方法区则成为了元空间的实现,同时元空间不再与堆连续,而且是存在于本地内存(Native memory)。
JVM内存模型
- 线程私有:程序计数器,虚拟机栈,本地方法栈
- 线程共享:MetaSpace、Java堆
程序计数器(Program Counter Register)
- 是一块较小的内存空间,可以看做是当前线程所执行的字节码行号的指示器;
- 字节码解释器工作时,通过改变计数器的值选取下一条执行的字节码指令;(一些基本功能都需要依赖计数器来完成 如 分支 循环 跳转 异常处理 线程恢复 等)
- 和线程一对一关系,即线程私有。java虚拟机多线程是通过线程间轮流切换来分配给处理器执行时间;在确定时间节点,一个处理器(一核)只会执行一个线程的指令;为保证线程切换回来后能恢复到原执行位置,各个线程间计数器互相不影响,独立存储(称之为线程私有的内存);
- 当线程正执行java程序时:程序计数器记录正在执行的虚拟机字节码指令地址;执行native方法,计数器值为 undefined;
- 不会发生内存泄漏,此内存区域是唯一一个java虚拟机规范中没有规定任何 OutOfMemoryError 情况的内存区域;
- 是逻辑计数器而非物理计数器
JAVA虚拟机栈(stack)
- Java方法执行的内存模型
- 每个方法在运行时都会创建一个栈帧,故包含多个栈帧
- 栈帧包括:局部变量表,操作数栈,动态连接,返回地址
- 当方法返回时帧才会被销毁
- 虚拟机栈包括了单个线程每个 方法执行的栈帧。
局部变量表和操作数栈
- 局部变量表:包含方法执行过程中的所有变量
- 操作数栈:入栈,出栈,复制,交换,产生消费变量
- 当一个方法刚刚开始执行时,其操作数栈是空的,随着方法执行和字节码指令的执行,会从局部变量表或对象实例的字段中复制常量或变量写入到操作数栈,再随着计算的进行将栈中元素出栈到局部变量表或者返回给方法调用者,也就是出栈/入栈操作。一个完整的方法执行期间往往包含多个这样出栈/入栈的过程。
递归为什么会引发Java.lang.StackOverflowError异常
- 每次调用都会创建一个栈帧,如果递归过深,超过虚拟栈的深度就会产生StackOverflowError异常
虚拟机栈过多会引发Java.lang.OutOfMemeryError异常
本地方法栈
- 与虚拟机栈相似,主要作用于标记了native的方法
元空间(MetaSpace)与永久带(PermGen)的区别
- JDK8以后,元空间替代了永久带
- 元空间使用本地内存,永久带使用jvm内存
- 故不会出现元数据内存不足的报错
- 元空间使用本地内存,永久带使用jvm内存
- 替换后的优势:
- 字符串常量池在永久带中,容易出现性能问题和内存溢出
- 类和方法的信息难确定大小,给永久带的大小指定带来困难
- 太小容易溢出,太大容易老年代溢出
- 永久带回为GC带来不必要的复杂度
- 方便HotSpot(虚拟机)与其他JVM如Jrockit的集成
Java堆(heap)
对所有线程共享
对象实例的分配区域
GC管理的主要区域
-
分代:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Alfred的小站!