JVM原理浅析

1. JVM运行时数据区

JVM原理浅析_第1张图片

  • 方法区:JVM用来存储加载的类信息、常量、静态变量、编译后的代码等数据。该部分数据是线程共享的。jdk1.8之前方法区放在永久代,jdk1.8开始方法区放在元空间,元空间并不在JVM中,而是使用本地内存。
  • 堆内存(heap):在JVM启动时创建,存放对象的实例。该部分数据是线程共享的。堆内存分为老年代和新生代。新生代又分为Eden和Survivor区。Survivor区由FromSpace和ToSpace组成。Eden区占大容量,Survivor两个区占小容量,默认比例是8:1:1。
  • 栈内存(stack):栈分为虚拟机栈和本地方法栈。
    虚拟机栈:在线程创建的时候,会分配一个独立的虚拟机栈,其它线程是无法访问当前线程的虚拟机栈的。虚拟机栈由栈帧组成,一个方法对应一个栈帧。栈帧内容包括局部变量表、操作数栈、动态链接、方法返回地址、附加信息等。
    本地方法栈:本地方法栈是虚拟机调用Native本地方法栈时使用。
  • 程序计数器:记录当前线程执行字节码的位置。在CPU切换线程使用权时,通过程序计数器来恢复当前线程在上次交出CPU使用权时程序执行到的位置,从而确保程序能连续正确的执行。

2. 堆内存的分代和垃圾回收

2.1 堆内存分代概念

新生成的对象首先放到年轻代Eden区,当Eden空间满了,触发Minor GC,存活下来的对象移动到Survivor0区,Survivor0区满后触发执行Minor GC,Survivor0区存活对象移动到Suvivor1区。经过多次Minor GC仍然存活的对象移动到老年代。
老年代存储长期存活的对象,占满时会触发Major GC=Full GC,GC期间会停止所有线程等待GC完成,所以对响应要求高的应用尽量减少发生Major GC,避免响应超时。
Minor GC : 清理年轻代
Major GC : 清理老年代
Full GC : 清理整个堆空间,包括年轻代和永久代
所有GC都会停止应用所有线程。

2.2 垃圾回收算法(GC,Garbage Collection)

  • 标记-清除(Mark-Sweep)
    GC分为两个阶段,标记和清除。首先标记所有可回收的对象,在标记完成后统一回收所有被标记的对象。同时会产生不连续的内存碎片。碎片过多会导致以后程序运行时需要分配较大对象时,无法找到足够的连续内存,而不得已再次触发GC。
  • 复制(Copy)
    将内存按容量划分为两块,每次只使用其中一块。当这一块内存用完了,就将存活的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。这样使得每次都是对半个内存区回收,也不用考虑内存碎片问题,简单高效。缺点需要两倍的内存空间。
  • 标记-整理(Mark-Compact)
    也分为两个阶段,首先标记可回收的对象,再将存活的对象都向一端移动,然后清理掉边界以外的内存。此方法避免标记-清除算法的碎片问题,同时也避免了复制算法的空间问题。
    一般年轻代中执行GC后,会有少量的对象存活,就会选用复制算法,只要付出少量的存活对象复制成本就可以完成收集。而老年代中因为对象存活率高,没有额外过多内存空间分配,就需要使用标记-清理或者标记-整理算法来进行回收。
    问题1:为什么分代?
    将对象根据存活概率进行分类,对存活时间长的对象,放到固定区,从而减少扫描垃圾时间及GC频率。针对分类进行不同的垃圾回收算法,对算法扬长避短。
    问题2:为什么survivor分成两块内存相等的S0和S1区?
    解决内存碎片化问题(内存碎片化是指对象占用不连续的内存,剩下未占用的连续内存不够新对象存放)。为垃圾回收算法“标记-清楚-复制”而准备。

你可能感兴趣的:(Java理论,#jvm原理)