模拟面试回答第十三问:JVM内存模型

JVM简介

JVM是Java程序运行的基石,包括程序计数器,两种栈,堆和方法区五个区域。包含保存类元数据,保存方法字节码执行顺序,保存符号引用与直接地址的映射,为对象实例分配内存,为堆中内存分配对象引用,指向下一条要执行的字节码等等,这都是JVM做的事。

内部区域划分

JVM的内部区域可按线程私有和线程共享划分,首先线程私有包括程序计数器和栈,线程私有就是说与线程的生命周期一致,随线程生和灭,每个线程都有各自的程序计数器和栈。其次线程共享包括堆和方法区,线程共享就是说与JVM、与进程的生命周期一致,随进程生和灭,所有线程共同使用堆和方法区。

内部区域详解

程序计数器

先说线程私有的部分,首先是程序计数器。

程序计数器是字节码指令顺序指针,保存下一条要执行的指令,执行顺序通过方法区Klass中的Method对象获取,这个程序计数器是五个区域中唯一的不会爆发OOM的区域。

栈分Java方法栈和本地方法栈,分别为Java方法和Native方法服务,Native方法就是C/C++语言写的。栈会在执行方法前为方法创建栈帧,栈帧中保存局部变量、操作数和Klass指针等等。这个区域是可能爆发栈溢出的,进而爆发OOM,如果递归没写好终止条件,会导致无限堆栈,就会发生栈溢出和OOM。

堆是JVM为对象实例分配内存的地方,保存对象的实际值,根据方法区的Klass明确分配多少内存。这里我重点关注了对象头区域。对象头包含了很多字段,包括哈希值,GC年龄,GC颜色,锁标志以及Klass指针。比如instanceof关键字判断对象所属类就可以通过Klass指针判断;还有hashCode计算出的哈希值保存在对象头中供哈希集合使用;发生GC时的对象头会被填充进GC年龄和GC颜色及其他信息来更好的GC,原信息要被暂时保存在GC线程中;还有保存锁的状态进行锁升级等等。堆是为对象实例分配内存的地方,那堆内存是有限的,一旦对象分配过多,导致堆内存不够了,怎么办?对象什么时候被删除?一个对象用完了之后怎么办,它分配的那块内存要收回吗?这就与JVM的垃圾回收机制有关,简称GC,GC能回收一些用完被判定为垃圾的对象,尽力防止对象填满堆的情况,所以堆是GC主要的工作区域,堆又被称为GC堆,这个区域是可能爆发OOM的。

方法区

方法区是JVM存储类元数据的地方,我们写的.class二进制字节码文件进入JVM方法区后,被组织成JVM运行时数据结构Klass,方法区以Klass为单位存储类元数据,Klass内部是有划分的,包括类的字段信息,类的继承信息,Method对象保存方法信息,常量池保存方法中符号引用与直接地址的映射,比如new User()这行代码被放在Method对象中,对于User这个符号,JVM需要得到这个类的Klass地址完成符号引用转直接引用才能生效为User分配内存。各个区域中都有保存各自的指针,通过指针访问。

这是方法区的大致构造,那方法区曾经不是独立的一块区域,而是在堆中,这样的实现方式叫做永久代,用永久代实现的方法区,使用堆的内存,那堆内存是比较有限的,分配给方法区的就更有限了,容易加载的类过多爆发OOM,那在JDK8之后,方法区独立出来由元空间实现,使用本地内存,本地内存非常大,不容易爆发OOM。

简单总结一下,类元数据放在方法区中,对象实例放在堆中,通过方法区Klass明确分配多大内存,对象实例的地址在栈中被引用,程序计数器指向下一行要执行的指令。

除此之外,还有执行引擎,负责编译执行Java程序,但执行引擎不属于JVM内存模型。

相关推荐
人工智能AI技术4 小时前
计算机专业面试必看!90%学生都踩过的算法面雷区
人工智能·面试
森林里的程序猿猿4 小时前
并发设计模式
java·开发语言·jvm
u0136863825 小时前
将Python Web应用部署到服务器(Docker + Nginx)
jvm·数据库·python
xlp666hub5 小时前
深度剖析 Linux Input 子系统(3):从零写一个 Input 驱动,最详细手把手(附完整代码)
linux·面试
Cosolar6 小时前
吃透这5种Agent模式,搞定智能体开发
人工智能·面试·全栈
njidf6 小时前
实战:用Python开发一个简单的区块链
jvm·数据库·python
骑龙赶鸭6 小时前
java开发项目中遇到的难点,面试!
java·开发语言·面试
AI成长日志6 小时前
【笔面试算法学习专栏】二分查找专题:力扣hot100经典题目深度解析
学习·算法·面试
我叫黑大帅6 小时前
Go 中最强大的权限控制库(Casbin)
后端·面试·go