Java虚拟机的JVM垃圾回收机制


1.JVM内存空间

  JVM堆(Heap)= 新生代(Young) + 旧生代(Tenured)

? 分区作用: 

新创建的对象通常先将其分配在新生代中,在新生代中经过若干次GC之后仍未释放的对象,再将它移动到旧生代。为了让内存回收更高效(GC会暂停JVM中的应用),Sun JDK在1.2开始对堆采用了分代管理的方式。在分配对象遇到内存不足时,先对新生代进行GC(Young GC);当新生代GC之后仍无法满足内存空间分配需求时, 才会对整个堆空间以及方法区进行GC (Full GC)

? 相关参数:

-Xms                       -- 设置堆内存初始大小

 -Xmx                       -- 设置堆内存最大值

-XX:MaxTenuringThreshold  -- 设置对象在新生代中存活的次数

-XX:PretenureSizeThreshold  -- 设置超过指定大小的大对象直接分配在旧生代中

? 注意点:当新生代设置得太小时,也可能引发大对象直接分配到旧生代中。

  新生代(Young)= Eden区 + Survivor区

? 分区作用:

Eden区为对象通常最初分配到的地方,Survivor区分为S0和S1两块大小相等的区域。JVM进行Minor GC时,将Eden中还存活的对象拷贝到Survivor区中,还会将Survivor区中还存活的对象拷贝到Tenured区中。在这种GC模式下,JVM为了提升GC效率, 将Survivor区分为S0和S1,这样就可以将对象回收和对象晋升分离开来。

? 相关参数:

-Xmn             -- 设置新生代内存大小。

-XX:SurvivorRatio  -- 设置Eden与Survivor空间的大小比例

? 注意点: 图中Virtual部分表示可伸缩的内存空间,当用-Xms在指定堆的初始大小为128m,通过-Xmx指定堆最大为256m时,JVM会根据内存情况在128m与256m之间伸缩。为了避免JVM进行这些伸缩消耗性能,对于能够提供稳定内存空间的用作服务器的JVM,通常将-Xms和-Xmx设置为相等。

  方法区(Perm)

? 分区作用:

也被成为持久代,用来存放JVM加载的类型信息。包括: 类型基本信息,常量池,字段信息,方法信息,类变量,指向ClassLoader的引用,Class类的引用,方法表等。方法区是全局共享的,在一定条件下也会被GC。

? 相关参数:

-XX:PermSize        --设置Perm区的初始大小

-XX:MaxPermSize    --设置Perm区的最大值

  JVM方法栈(注意:不是分区)

? 作用: 

JVM方法栈为JVM线程私有内存,当方法运行完毕后,其对应的栈帧内存会自动释放

? 相关参数:

-Xss                  --设置方法栈的最大值

? TLAB:

JVM所占用的主要内存都是从堆空间分配的,堆是所有线程共享的,因此在堆上分配内存需要加锁,Sun JDK为提升效率,会为每个新建的线程在Eden上分配一块独立的空间由该线程独享,这块空间称为TLAB(Thread Local Allocation Buffer)。其大小由JVM根据运行情况计算得到,也可通过参数-XX:TLABWasteTargetPercent来设置TLAB可占用的Eden空间的百分比,默认值为1%。在TLAB上分配内存不需要加锁,因此JVM在给线程中的对象分配内存时会尽量在TLAB上分配。如果对象过大或TLAB用完,则仍然在堆上进行分配。

2.Sun JDK GC收集器

收集器主要分为引用计数器和跟踪收集器两种,Sun JDK中采用跟踪收集器作为GC实现策略。

  跟踪收集器简介

跟踪收集器采用集中式的管理方式,全局记录数据的引用状态。触发执行时需要从根节点来扫描对象的引用关系,可能会造成应用程序暂停。主要有三种实现算法:复制(Copying) 、 标记-清除(Mark-Sweep) 、 标记-压缩(Mark-Compact) 。下文将简单介绍这三种算法的过程,有助于后续的GC策略理解和分析。

  复制(Copying)

? 算法:复制采用的方式为从根集合扫描出存活的对象,并将找到的存活对象复制到一块新的完全未使用的空间中。 ? 过程:注意,红叉为不存活的对象所占用内存空间

  标记-清除(Mark-Sweep)

? 算法:标记-清除采用的方式为从根集合开始扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未标记的对象,并进行回收。 ? 过程:

<!--[if !supportLists]-->ü   <!--[endif]-->优缺点:在空间中存活对象较多的情况下较为高效,但由于该算法为直接回收不存活对象所占用的内存,因此会造成内存碎片。

  • 1
  • 2
  • 下一页

相关内容