Java虚拟机在执行Java程序的过程中会把他所管理的内存划分为几个数据区域。
程序计数器(Program Counter Register)
程序计数器: 当前线程所执行的字节码的行号指示器,用于记录当前线程下一条需要执行的字节码指令
为了线程切换后能恢复正确的执行位置,每条线程都有一个独立的程序计数器
线程私有内存(各条线程间的程序计数器互不影响,独立存储)
若线程执行的是Java方法,计数器记录的是正在执行的虚拟机字节码指令的地址
若线程执行的是Native方法,计数器值为空(Undefined)
Java虚拟机栈(Java Virtual Machine Stacks)
线程私有,生命周期和线程相同
利用栈帧(Stack Frame)存储局部变量表、操作数栈、动态链接、方法出口等信息,每个方法的调用直至完成都代表一个栈帧在虚拟机栈中出栈入栈的过程
-
StackOverflowError异常: 当线程请求的栈深度大于虚拟机所允许的深度
OutOfMemoryError异常:虚拟机栈扩展时无法申请到足够的内存
局部变量表
存放了编译期可知的各种基本数据类型(int、btye等)、对象的引用和returnAddress类型(指向了一条字节码指令的地址)
其中64位长度的long和double占用2个局部变量空间(Slot),其余占一个
局部变量表所需的内存空间在编译期完成分配。当进入一个方法时,该方法在栈中分配的局部变量空间是完全确定的,在方法运行期间局部变量表不会改变大小
本地方法栈
与虚拟机栈的区别 :虚拟机栈为虚拟机执行java代码服务,本地方法栈为虚拟机使用到的Native方法服务
StackOverflowError和OutOfMemoryError
Java堆(Java Heap)
被所有线程共享的内存区域
用于存放对象实例
java堆可以是物理上不连续的内存空间,实现时既可以固定大小,也可以可扩展
OutOfMemoryError
方法区(Method Area)
-
线程共享,用于存储已经被虚拟机加载的类信息、常量、静态变量、编译后的代码等数据
运行时常量池
方法区的一部分。Class文件中的常量池,用于存放编译器生成的字面量和符号引用,这部分将在类加载后存入运行时常量池
运行时常量池和Class文件常量池的区别:运行时常量池具备动态性(并不一定只有编译器才会产生常量,代码运行期间产生的常量就可以放入运行时常量池,比如:String类的intern( )方法)