JVM 结构

(一)总体结构: 

JVM 结构

1)类加载子系统与方法区:类加载子系统负责从文件系统或者网络中加载Class信息,加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中可能还会存放运行时常量池信息,包括字符串字面量和数字常量(这部分常量信息是class文件中常量池部分的内存映射)。

2) java堆: java堆在虚拟机启动的时候建立,它是java程序最主要的内存工作区域。几乎所有的java对象实例都存放在java堆中。堆空间是所有线程共享的,这是一块与java应用密切相关的内存空间。

3)直接内存: java的NIO库允许java程序使用直接内存。直接内存是在iava堆外的、直接向系统申请的内存空间。通常访问直接内存的速度会优于java堆。因此出于性能的考虑,读写频繁的场合可能会考虑使用直接内存。由于直接内存在java堆外,因此它的大小不会直接受限于Xmx指定的最大堆大小,但是系统内存是有限的, java堆和直接内存的总和依然受限于操作系统能给出的最大内存。

4)垃圾回收系统:垃圾回收系统是java虚拟机的重要组成部分,垃圾回收器可以对方法区、java堆和直接内存进行回收。其中, java堆是垃圾收集器的工作重点。和c/C+不同, java中所有的对象空间释放都是隐式的,也就是说, java中没有类似free()或者delete(这样的函数释放指定的内存区域。对于不再使用的垃圾对象,垃圾回收系统会在后台黑埋工作,默默查找、标识并释放垃圾对象,完成包括java堆、方法区和直接内存中的全自动化管理。

5) java栈:每一个iava虚拟机线程都有一个私有的iava栈,一个线程的iava栈在线程创建的时候被创建, java栈中保存着帧信息, iava栈中保存着局部变量、方法参数,同时和java方法的调用、返回密切相关。

6)本地方法栈:本地方法栈和java栈非常类似,最大的不同在于java栈用于方法的调用,而本地方法栈则用于本地方法的调用,作为对java虚拟机的重要扩展, ava虚拟机允许java直接调用本地方法(通常使用c编写)

7) PC (Program Counter): PC寄存器也是每一个线程私有的空间, java虚拟机会为每一个java线程创建PC寄存器。在任意时刻,一个java线程总是在执行一个方法,这个正在被执行的方法称为当前方法。如果当前方法不是本地方法, PC寄存器就会指向当前正在被执行,的指令。如果当前方法是本地方法,那么PC寄存器的值就是undefined

8)执行引擎:执行引擎是java虚拟机的最核心组件之一,它负责执行虚拟机的字节码,现代虚拟机为了提高执行效率,会使用即时编译技术将方法编译成机器码后再执行。

 

Java HotSpot Client VM(-client),为在客户端环境中减少启动时间而优化;

Java HotSpot Server VM(-server),为在服务器环境中最大化程序执行速度而设计。

 

2, jvm堆结构图及分代,

Java虚拟机: JM内存分代策略

Java虚拟机根据对象存活的周期不同,把堆内存划分为几块,一般分为新生代、老年代和,永久代(对HotSpot虚拟机而言) ,这就是JVM的内存分代策略。

为什么要分代?

堆内存是虚拟机管理的内存中最大的一块,也是垃圾回收最频繁的一块区域,我们程,序所有的对象实例都存放在堆内存中。给堆内存分代是为了提高对象内存分配和垃圾回收的效率。试想一下,如果堆内存没有区域划分,所有的新创建的对象和生命周期很长的对象放在一起,随着程序的执行,堆内存需要频繁进行垃圾收集,而每次回收都要遍历所有的对象,遍历这些对象所花费的时间代价是巨大的,会严重影响我们的GC效率,这简直太可怕了。

有了内存分代,情况就不同了,新创建的对象会在新生代中分配内存,经过多次回收 4.仍然存活下来的对象存放在老年代中,静态属性、类信息等存放在永久代中,新生代中的对,象存活时间短,只需要在新生代区域中频繁进行GC,老年代中对象生命周期长,内存回收, ,的频率相对较低,不需要频繁进行回收,永久代中回收效果太差,一般不进行垃圾回收,还可以根据不同年代的特点采用合适的垃圾收集算法,分代收集大大提升了收集速率这些都是内存分代的好处

内存分代划分为新生代,老年代(1.7中还存在永久代),新生代细分为Eden,From Survivor,To Survivor

 

JVM 结构

2.1新生代(Young Generation)

新生成的对象优先存放在新生代中,新生代对象朝生夕死,存活率很低,在新生代中,常规应用进行一次垃圾收集一般可以回收70%~95%的空间,回收效率很高。

HotSpot将新生代划分为三块,一块较大的Eden空间和两块较小的Survivor空间,默认比例为8:1:1,划分的目的是因为HotSpot采用复制算法来回收新生代,设置这个比例是为了充分利用内存空间,减少浪费。新生成的对象在Eden区分配(大对象除外,大对象直接进入老年代),当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC.GC开始时,对象只会存在于Eden区和From Survivor区, To Survivor区是空的(作为保,留区域)。GC进行时, Eden区中所有存活的对象都会被复制到To Survivor区,而在FromSurvivor区中,仍存活的对象会根据它们的年龄值决定去向,年龄值达到年龄阀值(默认为15,新生代中的对象每熬过一轮垃圾回收,年龄值就加1,GC分代年龄存储在对象的header中)的对象会被移到老年代中,没有达到阀值的对象会被复制到To Survivor区。接着清空Eden区和From Survivor区,新生代中存活的对象都在To Survivor区。接着, From Survivor区和To Survivor区会交换它们的角色,也就是新的To Survivor区就是上次GC清空的FromSurvivor区,新的From Survivor区就是上次GC的To Survivor区,总之,不管怎样都会保证在一次GC之后是空的。GC时当ToSurvivor没有足够的空间放上一次新生代收集下来的的存活对象时需要依赖老年代来进行分配担保,将这些对象存放在老年代中。

2.2老年代(Old Generation)

在新生代经历了多次的GC后存活下来的对象会进入到老年代。

(二)jvm垃圾回收算法和收集器

1.1 引用计数法

原理是此对象有一个引用,则增加一个计数,删除一个引用,则减少一个计数,垃圾回收的得时候会回收引用计数为0的对象,但是不好处理循环引用的。

1.2复制算法

把内存划分为两个相等的区域,每次只是用一个区域。垃圾回收的的时候遍历当前使用的区域把正在使用的对象复制到另一个区域中,每次算法收集的只处理正在使用的对象,因此复制成本较小,同时,复制过去还能相应的进行内存的整理不会出现碎片问题,缺点是需要两倍的空间。

 

JVM 结构

1.3标记-清除算法

算法分为两个阶段,第一个阶段 从引用的根节点(初始引用)开始标记所有被引用的对象,第二阶段遍历整个堆把未标记的对象清除,此算法需要暂停整个应用,同时会产生内存碎片影响到存储。

 

JVM 结构

JVM 结构

 

 

1.4标记-整理算法

结合了标记-清除的和复制两个算法的优点,也分为两个阶段,第一个阶段从根节点开始标记所有被引用的对象,第二季阶段遍历整个堆,清除未被标记的对象,并且把其余的对象进行压缩到堆的一块内存去按照顺序排放此法避免了标记-清除的碎片问题,同时也避免了复制算法的空间问题。

 

JVM 结构

JVM 结构

 

jvm垃圾收集器

Minor(Scavenge GC)GC:指经常发生在新生代的GC,因为新生代的Java对象大多是生命周期较短的,所以Scavenge GC 会非常的频繁,回收速度也就较快当Eden空间不足内存分配的情况下就会触发Minor GC。

一般情况下,当新对象生成,并且在Eden 区申请空间失败时就会发生Scavenge GC对Eden 区域进行GC。清除非存活对象并且把尚且存活的对象移动到Survivor区,然后整理Survivor的两个区域,这种方式的GC对Eden进行GC不会影响到老年代因为大部分的对象都是从Eden 区域开始的,同时Eden区域不会分配的很大所以Eden的GC会频繁的进行因而一般在这里需要使用速度快点效率高的垃圾收集算法,以保证尽快的清理出可用空间。

老年代的GC:FullGC指发生在老年代的GC,出现FullGC 通常会伴随着至少一次的Minor GC,老年代的对象大部分是经过Minor GC 从新生代进入的,当老年代内存不足的时候会显示的调用System.gc()方法,会触发FullGC。

次收集器:当年轻代怼空间紧张的时候会被触发,相对于Full GC 来说,间隔时间较短。

(三)分代垃圾收集器

共7个,三个新生代,三个老年代,一个贯穿新生代和老年代。

新生代收集器:

Serial 收集器:串行化收集器,需要暂停程序是HotSpot运行在Client模式下的默认新生代的收集器,特点是只用一条线程去垃圾回收,虽然单线程但是简单高效。

 

相关文章:

  • 2022-12-23
  • 2021-09-05
  • 2021-08-17
  • 2021-07-01
  • 2022-12-23
猜你喜欢
  • 2021-10-30
  • 2021-05-23
相关资源
相似解决方案