JVM内存分区
JVM是一种用于计算设备的规范,通过在实际的计算机上仿真模拟各种计算机功能来实现的。
线程共享
堆heap
用于所有对象实例(包括数组),也是GC管理的主要区域,并且可以要求分配的地址不是物理连续的,只要逻辑连续即可
堆可更详细的分为下面几个区域
青年代 youngGeneration
青年带又具体分为
- Eden区
新生对象首先分配在Eden区,如果内存不够,发起一次Minor GC。是整个heap区中占比最大的 - From Survivor区
约为Eden的。如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区 - To Survivor区
老年代oldGeneration
大对象将直接建立在老年代中,此外Survivor区中对象存活年龄到达阈值也将进入老年区
关于对象在heap中的生命流程将在另一篇详细说明
该位置抛出OOM(OutOfMenory Error)
方法区
用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
实现方法之前是永久代 PermGen,现在替换为元空间 MetaSpace
为什么将PerGen替换为MetaSpace?
PermGen又JVM自身设置的固定上限,而MetaSpace直接使用系统内存,减少溢出的产生
关于方法区存储的类信息,详见: ʅ(´◔౪◔)ʃ
关于常量池和运行时常量池介绍见 ◐▽◑
同样该区域会抛出OOM
线程独享
程序计数器
当前线程所执行字节码的行号指示器
多线程切换后复原实现:
线程轮流切换,分配处理器时间。因而为了能使切换后继续执行而不至于从头来过,因此每个线程独立的程序计数器保存切换前的最后一条指令,在切换回来之后读取继续执行
JVM栈
java程序从启动到结束,实际就是main函数从入栈到出栈的过程,所以在说明JVM栈之前先讲解JVM栈的基本单位,Java方法执行的内存模型:
栈帧
其中局部变量表所占内存在编译器决定,运行期不会再改动。这里解释了为什么使用多态接受对象时,不能调用子类方法。
这里会抛出两个异常,一个是内存不够抛出的OOM,还有栈深度超过限制抛出的StackOverflow Error
native方法栈
与JVM栈的作用非常相似,区别是:虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法。
参考资料:
- JVM内存划分
- 24个Jvm面试题总结及答案
- 深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)