运行时数据区域

程序计数器
-
一块较小的内存空间
-
当前线程所执行的字节码的行号指示器
-
字节码解释器改变这个指示器的值来选择下一条执行的字节码指令
-
每条线程有一个独立的计数器(线程私有),目的保证在切换线程的时候保证能恢复到正确的执行位置
-
native方法计数器值为空,此区域没规定OOM
Java虚拟机栈
-
线程私有,生命周期与线程相同
-
Java执行的内存模型,在执行时创建栈帧,存局部变量表、操作数栈、动态链接、方法出口等信息
-
方法从调用到结束,对应着其栈帧入栈到出栈
-
局部变量表(编译期间完成分配,进入发发钱局部变量空间为完全确定的)
- 编译期可知的基本数据类型
- (boolean,byte,char,short,int,float.long,double)
- 64位long和double占用2个局部变量空间,其余数据类型只占用一个
- 对象引用,reference类型,是指向一个对象起始地址的引用指针、或指向一个代表对象的句柄或其他于此对象相关的位置
- returnAddress类型,指向一条字节码指令的地址
- 编译期可知的基本数据类型
-
栈深度大于虚拟机所允许的深度会抛出StackOverflowError
-
如果可以动态拓展,但无法申请到足够的内存,抛出OutOfMemory
本地方法栈
Differences between Natvie Method Stack
and Java Virtual Machine Stacks
-
本地方法栈虚拟机为Native方法服务
-
虚拟机栈为Java方法(字节码)服务
Java堆
-
虚拟机启动时创建
-
目的:
- 存放对象实例,几乎所有对象实例都在这里分配内存(!随着栈上分配、标量替换优化技术会导致所有对象分配在栈上不是那么绝对)
- 辣鸡收集器管理的主要区域(GC堆)
-
分类方式:
-
内存回收(分代收集算法):新生代和老年代
-
内存分配:划分出线程私有的分配缓冲区(TLAB)
-
-
无论哪个区域,储存的都是对象实例,与内容无关
-
可以处于不连续的内存空间中、逻辑需连续
-
怼中没有内存完成实例分配,并且堆无法再拓展时候,会抛出OutOfMemoryError
方法区
- 目的:用于储存已被虚拟机加载的类信息、常亮、静态变量、即时编译器编译后的代码
- Difference with heap
- heap经常发生GC进行垃圾收集,而方法区约等于“永久态”(! 不是永久存在,有对常量池的回收及对类型的卸载,但是条件比较苛刻)
- 个人理解主要目的是为了进行内存优化,像常亮这类不需要频繁GC的适合放在方法区
-
运行时常量池
- 方法区的一部分
- 存放编译器生成的各种字面量和符号引用
- 不一定是定义在Class文件内部的常量池才会进入运行时候常量池,运行期间有可能将新的常亮放入池中(String的intern())
- 无法再申请内存的时候抛出OutOfMemoryError
直接内存
- 不属于虚拟机运行时数据区
- 可以使用Native函数库直接分配heap外内存,通过Java堆中DirecrByteBuffer对象作为这块内存的引用进行操作
- 作用:提高性能,避免Java堆和Native堆中来回复制数据