参考了多位CSDN大佬的文章,在本文开头就先跪谢各位大佬的内容!! :)
可以按线程是否私有分为两大类:
- 线程私有的有程序计数器 (Program Counter Register)、虚拟机栈 (Java Stack)、本地方法栈 (Native Method Stack)
- 线程共享的有堆 (Heap)、方法区 (Method Area)
1. JVM 内存整体的结构(运行时数据区)和各自的功能
方法区(Method Area):
它是线程共享的内存区域,它用于存放已被虚拟机加载了的类信息、常量、静态变量、即时编译器编译后的代码等数据,同时方法区还维护了运行时常量池, 以下是相关的一些简单的例子:
Helloword.class (类信息)
常量:
public static final double PI = 3.14; // 静态常量
final int y = 10; // 成员常量
public static void main(String[] args) {
final double x = 3.3; // 局部成员常量
......
}
当方法区无法满足内存分配需求时,将抛出OutOfMemoryError
异常
运行时常量池位于方法区 - 进一步理解常量池可参考文章
JAVA常量池,一篇文章就足够入门了。(含图解)_河海哥yyds的博客-CSDN博客
堆(Heap):
它是线程共享的内存区域,在虚拟机启动时完成创建。这块内存区域的(唯一)目的就是存放对象实例,几乎所有的对象实例和数组都在这里分配内存,也就是说通过new关键字创建的对象都会使用堆内存 (e.g.: new Object(); new int[10])
如果在堆中没有完成实例分配,并且堆也无法扩展时,将会抛出 OutOfMemoryError
异常
程序计数器(Program Counter Register):
它是线程独享的内存区域,它可以被看作是当前线程所执行的字节码的行号指示器。用于保存JVM中下一条所要执行的指令地址 (通俗的讲就是在并发环境中,它负责告诉程序下一步该执行哪一条指令)
此区域是唯一一个虚拟机规范中没有规定任何OutOfMemoryError
情况的区域
虚拟机栈(Java Stack,也被叫做非堆 Non-heap):
它是线程独享的内存区域,是每个线程运行都需要的内存空间。
每个方法在执行的时候会创建一个帧栈(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口(Return address)等信息。
局部变量表:
存放一些基本类型变量(int, byte, short, char, float,double, long, boolean)和对象句柄,他们可以是方法的参数,也可以是方法内部的局部变量
操作数栈:运算操作等
动态链接:访问其他方法
方法出口:方法返回
它描述了一个方法执行的生命周期 (从方法执行时创建栈帧,并且压入栈,到方法执行完成压出栈),如果在方法中调用了另一个方法,那么就需要去创建另一个全新的栈帧去描述另一个方法的生命周期(入栈出栈。。。)
Java虚拟机栈有两种异常状况︰
1. 如果线程请求的栈的深度大于虚拟机所允许的深度将抛出StackOverflowError异常;
2. 如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
本地方法栈(Native Method Stack):
它是线程独享的内存区域,是保存一些带有native关键字的方法就是需要JAVA去调用本地的C或者C++方法,因为JAVA没法直接和操作系统底层交互,所以需要用到本地方法
与Java虚拟机栈一样,本地方法栈也会抛出StackOverflowError
和 OutOfMemoryError
异常