先放一张图
内存模型可以从不同的维度划分,最简单的就是从线程归属问题切入,分为两部分
- 线程私有区:不同线程理论上互相独立的部分
- 程序计数器,记录正在执行的虚拟机字节码的地址;
- 虚拟机栈:方法执行的内存区,每个方法执行时会在虚拟机栈中创建栈帧;
- 本地方法栈:虚拟机的Native方法执行的内存区;
- 线程共享区:需要注意并发问题的case
- Java堆:对象分配内存的区域;
- 方法区:存放类信息、常量、静态变量、编译器编译后的代码等数据;
- 常量池:存放编译器生成的各种字面量和符号引用,是方法区的一部分。
各区域介绍
1.程序计数器
整个内存中较小的一块,记录当前线程所执行的字节码行号指示器。idea或者eclipse在debug是,能精确到跳到执行的某一行,就是在追这个。当然,如果执行的是native的方法,计数器是0……
2.虚拟机栈
线程的生命周期也就是虚拟机栈的生命周期,每个线程中java方法调用和退出,就是在虚拟机栈的入栈到出栈。就像一个真正的栈,他有自己的栈帧(Stack Frame)结构。直接贴一段描述
- 局部变量表 (locals大小,编译期确定),一组变量存储空间, 容量以slot为最小单位。
- 操作栈(stack大小,编译期确定),操作栈元素的数据类型必须与字节码指令序列严格匹配
- 动态连接, 指向运行时常量池中该栈帧所属方法的引用,为了 动态连接使用。
- 前面的解析过程其实是静态解析;
- 对于运行期转化为直接引用,称为动态解析。
- 方法返回地址
- 正常退出,执行引擎遇到方法返回的字节码,将返回值传递给调用者
- 异常退出,遇到Exception,并且方法未捕捉异常,那么不会有任何返回值。
- 额外附加信息,虚拟机规范没有明确规定,由具体虚拟机实现。
3.本地方法栈
和上面差不多,也是方法栈,不过这个是native方法的。Sun HotSpot其实把2和3和在了一起的。
4.Java堆
就是几乎所有的对象和数组实例,一般GC其实就是针对这一块儿的
5.方法区
方法区主要存放的是已被虚拟机加载的类信息、常量、静态变量、编译器编译后的代码等数据。GC在该区域出现的比较少。
6.运行时常量池
编译class期间,发现的static final常量+字符串的所在地