目录
JVM主要内存模型
JVM运行时数据区:
运行时数据区执行流程:
1、程序计数器(PC-Program Counter Register)
特点:
2、栈(Stack)
特点:
存储内容:
2种异常:
StackOverflowError异常:
OutOfMemoryError异常:
3、堆(Heap)
对象的内存分配:
特点:
存储内容:
异常:
OutOfMemoryError异常:
4、方法区(Method Area)
特点:
存储内容:
异常:
OutOfMemoryError异常:
5、运行时常量池(Runtime Constant Pool)
特点:
存储内容:
异常:
OutOfMemoryError异常:
本地方法(Native):
Native Method Stack:
直接内存(DirectMemory)
异常:
OutOfMemoryError异常:
是一块较小的内存空间,是当前线程所执行的字节码的行号指示器。
每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,也即将执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎忽略不计。
由于java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(单核)都只会执行一条线程指令。因此,为了线程切换后能回复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互补影响,独立存储。
此内存区域是唯一一个JVM规范中没有规定任何OutOfMemoryError情况的区域
每个方法执行都会创建一个栈帧:存储局部变量表、操作数栈、动态链接、方法出口等信息。
进栈、出栈(后进先出)
如果线程请求的栈深度 > 虚拟机所允许的深度。
示例:
如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存
1.对象优先在Eden分配
对象优先进入eden新生代分配——当Eden没有足够空间进行分配时,进行Minor GC。——将Eden存活对象放入Survivor(如果空间不足,直接放入老年区
2.大对象直接进入老年代
-xx:PretenureSizeThreshold参数,令大于这个值的对象直接在老年代分配。
目的:避免在Eden区以及两个Survivor区发生大量的内存复制
3.长期存活的对象将进入老年代
对象年龄计数器:对象在Eden出生并且经历过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且对象年龄设置为1.对象在Survivor每熬过一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就将会被晋升到老年代中。对象晋升老年代的阈值,可以通过参数:-XX:MaxTenuringThreshold设置。
4.动态对象年龄判断
并不是必须导到晋升老年代的阈值才会晋升,如果在Suvivor空间中相同年龄对象大小综合大于Survivor空间的一般,年龄大于或等于该年龄的对象就可以直接进入老年代。
5.分配担保
如果在堆中没有内存完成实例分配,并且堆也无法再扩展时。
原因:1.Java虚拟机的堆内存设置不够,可以扩展通过(-Xmx和-Xms控制);2.代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)
方法区无法满足内存分配需求时。
当常量池无法再申请到内存时会抛出此异常
调用底层方法的接口
Native Method Stack中登记native方法,在Execution Engine执行时加载本地方法库。
不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。
但这部分内存被频繁地使用,也可能导致OutOfMemoryError异常出现。