课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
JVM内存模型我程序员在学习java编程开发的时候需要重点学习的编程技术之一,而今天我们就一起来了解一下,JVM内存模型的常见类型都有哪些。
1、JVM内存模型
了解JVM内存模型,先要搞清楚这四个概念
.class文件:.java文件通过编译器编译后,存储在硬盘上的文件
classcontent:类加载器将硬盘中的.class文件加载到直接内存中的那块区域之后就成为classcontent,此时classcontent内容和class文件是一样的
class对象:类加载器基于虚拟机规范将内存中的classcontent解析成class对象,放入方法区中
对象:执行引擎在执行new操作的时候,会将class对象生成对象,放入堆中
2、方法区
方法区是模型,具体的典型实现有Hotspot在1.8之前的永久代实现和1.8及以后的元空间实现
永久代实现是HotSpot的设计团队选择把垃圾回收器的分代设计扩展至方法区。使用永久代来实现方法区。使得Hotspot的垃圾回收器能像管理Java堆一样管理方法区的这部分内存,省去专门为方法区编写内存管理代码的工作。因为永久代有大内存限制,这种设计导致Java更容易oom。而元空间策略只要不触及物理内存上限就没多大事
3、方法区为什么由永久代实现改成元空间实现?
在JDK1.8以前,市面上的操作系统大部分还是32位,而32位操作系统大支持4GB内存,这时如果程序出现死循环或其他原因而疯狂创建新对象占用内存空间,则硬件内存很容易被撑爆。因此JVM通过永久代实现来管理内存,紧紧把我内存的使用权限;随着硬件的发展,64位操作系统占据主流市场,大支持256TB内存,市面上主流机器的内存也不断增加。另外Spring等框架在一启动就会创建很多的class对象,JVM管理起来很吃力。因此JVM在JDK1.8之后索性放松这块的限制,变成了元空间实现
4、程序计数器
记录着虚拟机栈中每个方法执行的位置,可以看作是当前线程所执行的字节码文件的行号指示器。Java程序中分支、循环、跳转、异常处理、线程恢复等操作都需要程序计数器才能完成。
Java虚拟机的多线程是由多线程轮流切换、分配处理器执行时间来实现的。在任何一个确定的时刻,一个内核都只会执行一个线程。因此Java中每个线程都有自己的程序计数器来确保线程切换后能回到准确的位置
5、虚拟机栈
每个线程都有自己的虚拟机栈,局部变量是存储在虚拟机栈中的,因此不存在并发问题
每个虚拟机栈又有很多个栈帧,每个方法在执行的时候,虚拟机会同步创建一个栈帧,包含了:局部变量表、操作数栈、动态链接、方法出口/返回地址(恢复现场)、附加信息这些部分
局部变量表:存储该方法编译期可知的各种Java基本类型、对象引用和returnAddress类型。这些数据类型在局部变量表中的存储空间以局部变量槽(Slot)来表示,其中64位长度的long、double类型占2个槽,其余的数据类型占1个
操作数栈:变量赋值操作等号右边的部分
动态链接:指向该方法在方法区的地址,虚拟机图示中虚拟机栈指向方法区的棕色箭头便是表示的动态链接
返回地址(恢复现场)该方法弹栈后,恢复现场进行了如下的操作
局部变量表指针重置
操作数栈指针重置
返回值压栈
该方法占用的栈帧内存回收
程序计数器的数值重置
附加信息:HotSpot并没有对此进行实现
当线程请求的栈深度大于虚拟机允许的深度时,会报StackOverflowError异常
当无法申请到足够的内存时,会OOM
本地方法栈
和虚拟机栈类似,区别在于运行的是native方法,HotSpot中把本地方法栈和虚拟机栈合二为一
6、Java堆
所有的对象实例及数组几乎都在堆中分配
为什么老年代的空间是新生代的2倍?
老年代存在两种对象:
在新生代经过15次GC还没有被回收的对象
大小超过伊甸园(Eden区)的大对象,直接放到老年代。避免了对象在新生代三个区之间的复制、避免了新生代三个区被撑爆
可以看出老年代存储的都是大对象/老对象。另外老年代也是一种空间担保机制,避免由于新生代空间的限制导致的内存问题。因此需要更大的内存空间
【免责声明】:本内容转载于网络,转载目的在于传递信息。文章内容为作者个人意见,本平台对文中陈述、观点保持中立,不对所包含内容的准确性、可靠性与完整性提供形式地保证。请读者仅作参考。更多内容请在707945861群中学习了解。