认识Java虚拟机-JVM内存结构

目录

一. JVM内存结构

(一)Java栈(Java Stack)

(二)本地方法栈(Native Method Stacks)

(三)程序计数器(The PC Register)

(四)Java堆(Java Heap)

1、新生代(Young Generation)

2、老年代(Old Generation)

(五)方法区(Method Area)

元空间(Meta Space)


一. JVM内存结构

JVM的内存结构说的就是运行时数据区,该区域又分成五个内存结构:

  1. 线程私有:Java栈、本地方法栈、程序计数器
  2. 线程共享:堆、方法区

下面开始对每个结构进行讲解。

(一)Java栈(Java Stack)

  • 该区域是JVM内存结构中最重要的区域,它是Java线程执行方法的内存模型,每个线程都会拥有自己独立的栈区,不与其他线程共享;
  • 线程中的每个方法在执行时都会创建一个属于该方法的栈帧(Frames),用于存储局部变量表(Local Variables)、操作数栈(Operand Stacks)、动态链接(Dynamic Linking)、方法出口信息等
  • 对于八种基本数据类型(byte、short、int、long、float、double、char、boolean)的局部变量,在栈中存储的是它们对应的值;
  • 对于定义定义在方法体中的引用类型的变量存储的是对象引用,不是对象本身,对象引用是对象在堆中的地址;
  • Java栈不需要进行垃圾回收,因为它的生命周期是跟线程一致的,只要线程执行完,就会被释放掉。

JVM为该区域定义了下面两种异常类型:

  • 线程请求的栈深度大于虚拟机栈所允许的深度,将抛出StackOverFlowError异常
  • 若虚拟机栈可动态扩展,当无法申请到足够内存空间时将抛出OutOfMemoryError
  • 通过jvm参数–Xss指定栈空间,空间大小决定函数调用的深度

 

(二)本地方法栈(Native Method Stacks)

本地方法栈也是一个栈结构,并且是线程私有,作用是登记本地方法,即native方法,JVM执行引擎会在执行时加载本地方法库。

 

(三)程序计数器(The PC Register)

程序计数器是一个线程私有的指针,它指向了方法区中的方法字节码,记录线程即将要执行的程序指令位置,交由执行引擎读取下一条指令然后执行。

 

(四)Java堆(Java Heap)

  1. Java堆是线程共享的内存区域。它会在虚拟机在启动时创建。
  2. Java堆唯一目的就是存放对象实例,所有的对象实例、实例变量(不包括static修饰的成员变量)及数组都要在Java堆中分配内存空间,当空间耗尽无法继续分配内存时会抛出OutOfMemoryError异。
  3. 该区域也是垃圾收集器管理的主要区域;
  4. 可以通过设置-Xmx、–Xms参数指定最大堆、最小堆的值。

堆结构详解

堆大小=新生代+老年代。

1、新生代(Young Generation)

默认占堆大小的1/3,是类诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾收集器收集消亡。

新生代分成两个部分:

  • 伊甸区(Eden Space)

所有的类都是在伊甸区被new操作创建。

  • 幸存者区(Survivor Space)

幸存者区也分成了两个区域,0区(Survivor 0 space)和1区(Survivor 1 space)。当伊甸区空间耗完而程序又需要创建对象时,JVM 的垃圾收集器将对伊甸区进行垃圾回收(Minor GC),对其中所有已经失去引用的对象实例进行销毁,然后将剩余的对象移动到幸存者0区,如果之后幸存者0区也满了,再对0区进行垃圾回收,然后将剩余对象移动到1区。

  • Survivor中的From与To区

刚才已经说明了Survivor区分为0区和1区,除此之外还有另一个概念,From Space与To Space。这两个区是相对的,在JVM没有触发Minor GC前,0区对应From,1区对应To,但是每触发一次Minor GC后,from区就会和to区互换。在发生Minor GC时,Eden区和Survivor-from区会把一些仍然存活的对象复制进Survivor-to区,然后清理空间,并且将此时在Survivor空间中存活的对象的年龄设置为1,以后Survivor区的这些对象每熬过一次GC年龄就加1,当对象年龄达到某个值时(默认是15),它们就会移到老年代中。

2、老年代(Old Generation)

该区域占堆大小的2/3,JVM会将新生代中经过多次GC后还存活的对象移动到老年代区,如果老年区满了,将通过Major GC(Full GC)对老年代和新生代中不再被使用的对象资源进行回收;如果在老年代区进行Full GC后发现依然无法申请内存空间来创建对象,这时就会产生OOM异常(OutOfMemoryError)。

需要注意的是,GC在运行的过程中都会发生STW(Stop The World)现象,暂停JVM中运行的所有业务线程,集中系统资源更高效地进行垃圾回收工作;但是不是所有GC收集器都是会暂停业务线程进行GC工作,CMS收集器和G1收集器是可以做到GC线程和业务线程并发执行的,这块知识点以后会在另开一篇垃圾回收机制的文章中介绍。

 

(五)方法区(Method Area)

方法区跟Java对一样是各个线程共享的内存区域,它存储已被Java虚拟机加载的类信息、常量、静态变量、静态方法和普通方法字节码信息、以及一些即时编译器编译后的代码等;当我们通过new关键字创建一个类的实例对象时需要的类定义信息就是从这里获取,方法区还有另一个别名叫做非堆(Non Heap)。

1、元空间(Meta Space)

从jdk1.8开始元空间取代了之前的java堆的永久代(Permanent Generation),本质上元空间和永久代是类似的,都是对JVM规范中方法区的实现。

两者的区别在于元空间的内存大小并不是JVM分配,而是直接使用本地物理内存;而永久代是在JVM中,永久代在逻辑结构上是属于堆,但是物理结构上不属于堆;元空间也有可能发生OutOfMemory异常。

  • Jdk1.6及之前: 有永久代,常量池在方法区
  • Jdk1.7:            有永久代,但已经逐步“去永久代”,常量池在堆
  • Jdk1.8及之后: 无永久代,常量池在元空间

元空间的动态扩展,默认–XX:MetaspaceSize值为21MB的高水位线。一旦触及这个大小限制,则Full GC将被触发并卸载没有用的类(类对应的类加载器不再存活),然后高水位线将会重置。新的高水位线的值取决于GC后释放的元空间。如果释放的空间少,这个高水位线则上升。如果释放空间过多,则高水位线下降。

 

参考资料:

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值