本地方法 | 非java代码实现的java方法,使用native关键字,除abstract外可与java关键字连用 |
程序计数器 | 可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等基础功能。该区域时java虚拟机规范中没有规定outofmeroryError情况的区域 |
虚拟机栈
|
1、生命周期同线程一致
2、程序员通常指的栈内存区,更确切的是指虚拟机栈中的局部变量表部分
3、局部变量表存放编译器的各种基本数据类型,对象引用
4、线程请求的栈深度大于虚拟机所允许的深度时抛出stackOverFlowError
5、当虚拟机在扩展时申请不到足够的内存的时候会抛出OutOfMemoryError
6、虚拟机栈描述的是java方法执行的内存模型:每个方法在执行的时候都会创建一个栈帧(stack frame),用于存放局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法从调用到执行完成就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
|
本地方法栈 |
1、功能同虚拟机栈,只不过该区域执行的是native方法
2、同虚拟机栈一样会抛出stackOverFlowError和outOfMemoryError
3、有些虚拟机将本地方法栈和虚拟机栈合二为一
|
Java堆 |
1、Java虚拟机所管理的内存中最大的一块
2、存放几乎所有的对象实例
3、GC管理器的主要管理区域
4、根据GC的分代算法将堆分为新生代和老年代,或者更细的分为Eden空间,From Suvivor空间,To Suvivor空间
5、堆为线程共享区
6、从内存分配的角度来看,堆中可以划分出多个线程私有的分配缓冲区(TLAB)
7、对内存的划分是为了更好的回收内存和分配内存
8、Java堆在逻辑上是连续的,在物理上可以不连续
9、大小可调,通过-Xmx和-Xms参数调节大小
10、当堆中没有内存分配给新创建的对象实例,并且堆无法再扩展的时候就会抛出outOfMemoryError
|
方法区 |
1、线程共享区
2、存储虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码
3、俗称永久代
4、通过参数-XX:MaxPermSize来限制方法区的大小
5、该区域的内存回收主要针对常量池和对类型的卸载
6、当该区无法满足内存分配的需求的时候会抛出oytOfMemoryError
|
运行时常量池 |
1、方法区的一部分
2、class文件中存放编译期生成的各种字面量和符号的引用的常量池信息,在加载完后放入运行时常量池
3、抛出outofMemoryError的情况同方法区
|
直接内存 |
1、不是虚拟机运行时数据区的一部分
2、不受堆内存大小的限制
3、NIO使用Native函数库直接操作堆外内存提高性能,但是如果堆内存分配不合理,就会导致动态扩展的时候抛出outOfMemoryError
|
内存分配与回收策略
- 对象优先在新生代Eden区分配
大部分对象创建的时候会在新生代的Eden空间分配空间,当Eden区没有足够的空间时,JVM会发起一次Minor GC
- 大对象直接进入老年代
大对象是指需要大量连续的内存空间的Java对象,典型的大对象就是那种长字符串和长数组,大对象经常会导致内存空间还有,但提前触发了GC来腾出空间安置他们。虚拟机提供参数-XX:PretenureSizeThreshold,所需内存超过该参数值的对象直接分配在老年代
- 长期存活的对象将进入老年代
虚拟机给每个对象定义了一个年龄计数器,当对象在Eden区出生并且经历一次Minor GC后依然存活并且能被Survivor容纳的话,该对象将会被移到Survivor区并且对象年龄加一,当它的年纪达到一定值(默认是15)时就会被移到老年代,如果老年无法存放的话就会发起一次Full GC,对于晋升老年代的对象年龄阀值可以通过参数-XX:MaxTenuringThresHold来设置
- 动态对象年龄判断
通常情况下新生代的对象必须达到对象年龄才会放入老年代,但是如果Survivor区中同一年龄的对象占用的总内存大于Survivor空间的一半,那么Age>=该年龄的对象直接放入老年代
- 空间分配担保
在发生Minor GC之前,虚拟机会先检查老年代最大的连续空间是否大于新生代所有对象的总空间,如果大于则可以保证此次Minor GC是安全的,如果不成立,则虚拟机会查看-XX:HandlePromotionFailure的值是否允许担保失败,如果允许则发起Minor GC,尽管此次GC是非安全的,如果不允许则发起一次Full GC