详解JVM的内存结构模型

众说周知,Java语言号称跨平台,一次编写,到处运行,而这离不开Java虚拟机(JVM)的存在。

Java并非JVM的唯一语言选择,Java虚拟机是定义了自己的JVM规定(字节码文件.class),只要符合JVM规范便可在JVM上运行。如今也出现了其他一些可以在Java虚拟机上运行的语言,例如Kotlin、Scala。理解JVM内存模型,也能帮助我们更好的理解程序的运行。

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区,不同的区域有着不同的作用,具体如下:

上图中,灰色部分则是线程共享的数据区,白色的则为线程隔离。各个区域的作用简单可以总结成如下:

虚拟机栈线程私有,生命周期跟线程相同,存储局部变量表,操作数栈,动态链接以及方法的出口等信息。每一个方法从调用到执行接口,就对应于一个栈帧在虚拟机栈中的进栈和出栈
Java堆线程共享,在虚拟机启动时创建,存储所有创建的对象实例。
方法区线程共享,该区域跟堆很类似,存储是已被加载的类信息,常量,静态变量以及即时编译后的代码,常量池就在该区域。
本地方法栈线程私有,为虚拟机使用到的Native方法服务
程序计数器线程私有,记录程序当前运用的所在的行数

Java堆是JVM管理内存中最大的一块区域,存放的是对象的实例而对象存在生命周期,因而为了避免内存溢出,也伴随着出现JVM对内存的分配和回收的问题。

内存的分配,虚拟机遇到new指令时,首先会去检查该指令的参数能否在常量池找到这个类的符号引用,并且检查这个类是否被加载、解析和初始化过。如果没有,则先执行类加载过程。如果已被加载,则为对象分配内存空间,分配的方式有两种:

  • 指针碰撞,通过移动指针分配空闲空间,因此内存绝对规整
  • 如果已使用和空闲内存相互交错,没法使用指针碰撞,则采用空闲列表。JVM需要维护一个列表记录哪些内存块可用

常量池存在于方法区中,是方法区的一部分。存放编译时期生产的各种字面量和符号引用。字面量接近于Java中的常量,而符号引用包括:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。JVM对方法区的回收主要就集中在对常量池的回收和对类的类型的卸载。

从内存回收的角度看,Java堆又分成新生代和老年代,新生代又分为Eden空间,Survivor空间,两者默认比例是8:1。对象创建时会默认存在Eden区域,新生代进行GC(垃圾回收)时候,会将存活的对象移动到Survivor空间,同时存活年龄+1,当对象的存活年龄大于15则会进入老年代。如果对象创建时太大,新生代触发一次GC后对象放不下也会直接进入老年代。

分代的主要目的是为了更好的内存回收和空间分配。年轻代中的存在许多生命周期比较短的对象,而老年代中的对象大部分生命周期较长,出于回收效率的考虑,JVM可以针对不同的空间执行不同的回收策略,像HotSpot对于新生代采用复制算法,老年代则采用标记清除算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

自平衡Azure

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值