Java内存区域与内存溢出异常
(一)运行时数据区域
可参考
https://www.zhihu.com/question/20097631
https://blog.csdn.net/TJtulong/article/details/89598598
https://www.cnblogs.com/chanshuyi/p/jvm_serial_00_why_learn_jvm.html

1、程序计数器(Program Counter Register)
(1)程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器;
(2)程序计数器处于线程独占区;
(3)如果线程执行的是java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址。而如果是native方法,这个计数器的值则为空(Undefined);
(4)此内存区域是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域;
2、Java虚拟机栈(Java Virtual Machine Stack)
虚拟机栈描述的是java方法
执行的动态内存模型。
栈帧(方法运行时的基本数据结构)
每个方法执行,都会创建一个栈帧,
伴随着方法从创建到执行完成
。用于存储局部变量表
,操作数栈,动态链接,方法出口等;
局部变量表
1)存放编译器可知的各种基本数据类型,引用类型,returnAddress类型。
2)局部变量表的内存空间在编译器完成分配,当进入一个方法时,这个方法需要在帧分配多少内存是固定
的,在方法运行期间是不会改变局部变量表的大小。
3)大小:
StackOverflowError
:线程请求的栈深度大于虚拟机所允许的深度;
OutOfMemoryError
:如果蓄奴籍栈可以动态扩展(大部分都可以),而扩展时无法申请到足够的内存;
3、本地方法栈(Native Method Stack)
本地方法栈于虚拟方法栈所发挥的作用时非常相似的
区别:本地方法栈为虚拟机执行native方法服务;
虚拟机栈为悉尼及执行Java方法服务;
4、Java堆(Java Heap)
Java堆是Java虚拟机所管理的内存中最大的一块,被所有线程共享
,在虚拟机启动时创建
(1)目的:存放对象实例 ;
(2)垃圾收集器管理的主要区域(GC堆,Garbage Collected Heap):新生代(Eden空间、From Survivor空间、To Survivor空间等)、老年代;另外,还可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB);
(3)OutOfMemoryError
:堆中没有内存完成实例分配,并且堆也无法再扩展时抛出;
(4)不需要连续的内存空间,逻辑连续就行。
5、方法区(Method Area)
(1)方法区是线程共享的内存区域,用于存储已被虚拟机加载的类信息(类的版本、字段、方法、接口)、常量、静态变量、即时编译器编译后的代码等数据;
(2)HotSpot虚拟机上吧方法区成为“永久代”(Permanent Generation),本质上两者并不等价,只是能省去专门为方法区编写内存管理代码的工作;
(3)方法区的垃圾回收效率很低;
(4)OutOfMemoryError
:和堆类似。

(上面说到,jdk1.8 中,已经不存在永久代(方法区),替代它的一块空间叫做 “ 元空间 ”,和永久代类似,都是 JVM 规范对方法区的实现,但是元空间并不在虚拟机中,而是使用本地内存,元空间的大小仅受本地内存限制,但可以通过 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 来指定元空间的大小。)
6、运行时常量池(Runtime Constant Pool)
上面提到的类文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是
常量池
,用于存放编译期生成的各种字面量和符号引用,这部分内容会在类加载之后进入运行常量池。
(1)运行时常量池具有动态性
,运行期间也可以讲常量放入池中,比如String类的intern()方法;
https://blog.csdn.net/tyyking/article/details/82496901
(2)OutOfMemoryError
7、直接内存(Direct Memory)
直接内存并
不是
虚拟机运行时数据区的一部分,也不是
javca虚拟机规范中定义的内存区域;而且也会出现OutOfMemoryError
异常。
网友评论