Java自动垃圾回收(Automatic Garbage Collection)是自动回收堆上不再使用的内存,new的对象在程序中没有引用指向它,就会被回收。回收的实现很多,有Reference Counting Collector/Tracing Collector/Compacting Collector/Coping Collector/Generational Collector/Adaptive Collector。本文记录的是HotSpot Java VM采用的Generational Collector(分代收集器)

为什么分代?

下图是随着时间的推移,经历垃圾回收后存活下的数据大小情况。可以看出大部分对象存活期很短,随着时间的推移越来越少的对象存活下来。因此,可以针对不同的堆内存采取不同的回收频率和方法,以提高JVM性能。

堆内存分代概念

下图是Generation GC对内存结构的划分:

Eden:用于new对象时分配的内存空间,大部分初始new的对象位于该空间

Survivor Space:在eden中经历垃圾回收后,存活下来的对象被存储在该空间

tenured Space:在survivor space中存在了一段时间的对象会被挪到该空间

Permanent Space:JVM使用的元数据,如classloader加载的class/method定义(反射后的数据)。

Code Cache:用于编译和存储原代码

其中Permanent Space和Code Cache不属于generation collector回收范围。但是当Permanent Space已用完,且需要加载新class时,会触发Full GC对Permanent进行回收,卸载(清除)那些不再被需要的class。

如何分代收集

new对象会最初分配在eden中,当eden满时触发minor garbage collection。

Minor GC(又称作Young GC)针对young generation:

  • eden/S0中存活的对象被复制到S1中,eden/S0被清空
  • 每次minor gc,存活对象的age会加1,当age超过阈值后,对象被存到old generation中。
  • S0和S1是相对的,第一次Minor GC时S0/S1都是空的,从eden往S0复制,第二次minor gc就是从eden/S0往S1复制,下一次是eden/S1到S0,以后依次类推。

Minor GC采用的是复制收集,young generation中的对象大部分是不再使用,所以复制存活下来的对象到新空间,旧空间整体回收,这样的一个过程会更快。

随着Minor GC的发生,被promoted到old generation的对象越来越多,当old generation满时就触发了major garbage collection。Major GC(又称作Old GC)针对old generation,采取marking-deletion-compact(标记-清除-压缩内存)的方法。(补:压缩内存,就是把活着的对象放在一块,省出连续的空闲内存,便于分配)

通常Major GC又被认为是Full GC,因为Major GC发生时会伴随着Minor GC:一次Minor GC将存活对象放到old generation时导致old generation满了,从而导致Major GC。这一段时间整个堆内存表现出的现象是都进行了garbage collection。

建议

Minor/Major GC都是Stop the World事件,应用程序会停止执行,直到GC完成。Major GC发生时,整个堆内存都受到了影响,持续时间长。

所以应该尽量避免或减少Major GC(减少被放到old generation的对象);尽量最大化堆内存。

实际使用

启动java程序时通过设置相关命令参数调节垃圾回收的方法、阈值或频率来优化GC对程序的影响,常用命令如下:

Switch Description
-Xms Sets the initial heap size for when the JVM starts.
-Xmx Sets the maximum heap size.
-Xmn Sets the size of the Young Generation.
-XX:PermSize Sets the starting size of the Permanent Generation.
-XX:MaxPermSize Sets the maximum size of the Permanent Generation

GC的串并行

串行GC在JavaSE 5/6上是默认方式,常用于对暂停时间要求不高、客户端类型的应用程序上,也适用于应用程序的数目比CPU多的情况,这样GC时JVM之间的影响小。MB级别的堆内存进行Full GC时只需要几秒。设置的命令是-XX:+UseSerialGC。

并行GC使用多线程进行Minor GC,线程数默认与CPU数相等。设置的相关命令是-XX:+UseParallelGC和-XX:ParallelGCThreads=<desired number>(指定线程数)。-XX:+UseParallelOldGC会设置Minor GC和Major GC都采用多线程。

CMS

并发标记清除收集器(Concurrent Mark Sweep)用于old generation的垃圾回收,它尽力减少程序的暂停时间,GC工作和应用程序的线程并发执行。它不做compact(压缩)堆内存,省去了内存的拷贝和移动。当内存碎片过多无法满足分配时,就直接重新分配一块更大的堆内存。CMS适用于webserver或者查询类的应用

相关命令:-XX:+UseConcMarkSweepGC和-XX:ParallelCMSThreads=<n>(设置并行线程数)

G1 Garbage Collector

G1回收器在Java7中被引进,希望能取代CMS,它主要是并发、增量式的compact内存,以取得低暂停。相关命令:-XX:+UseG1GC

一个实例

java -Xmx12m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseParallelOldGC -jar Java2demo.jar

参考:http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

JVM系列-分代收集垃圾回收的更多相关文章

  1. JVM的永久代会发生垃圾回收吗?

    垃圾回收不会发生在永久代中.当永久代满或者超过临界值时,就会触发完全垃圾回收(Full GC).如果仔细查看垃圾收集器中的输出信息,就会发现永久代也是被回收的.这就是正确的永久代大小对避免Full G ...

  2. JVM的stack和heap,JVM内存模型,垃圾回收策略,分代收集,增量收集

    (转自:http://my.oschina.net/u/436879/blog/85478) 在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认 ...

  3. JVM虚拟机学习一:垃圾回收算法总结

    1.java虚拟机中涉及到的数据类型 Java虚拟机中,数据类型可以分为两类:基本类型和引用类型. 基本类型的变量保存原始值,即:他代表的值就是数值本身:而引用类型的变量保存引用值.“引用值”代表了某 ...

  4. 推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题(图解版)

    欢迎一起学习 <提升能力,涨薪可待篇> <面试知识,工作可待篇 > <实战演练,拒绝996篇 > 欢迎关注我博客 也欢迎关注公 众 号[Ccww笔记],原创技术文章 ...

  5. JVM之GC算法、垃圾收集算法——标记-清除算法、复制算法、标记-整理算法、分代收集算法

    标记-清除算法 此垃圾收集算法分为“标记”和“清除”两个阶段: 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记对象,它的标记过程前面已经说过——如何判断对象是否存活/死去 死去的对象就会 ...

  6. JVM垃圾收集算法——分代收集算法

    分代收集算法(Generational Collection): 当前商业虚拟机的垃圾收集都采用"分代收集算法". 这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分 ...

  7. JVM的内存分配与垃圾回收策略

    自动内存管理机制主要解决了两个问题:给对象分配内存以及回收分配给对象的内存. >>垃圾回收的区域 前面的笔记中整理过虚拟机运行数据区,再看一下这个区域: 注意在这个Runtime Data ...

  8. Java虚拟机:JVM内存分代策略

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! Java虚拟机根据对象存活的周期不同,把堆内存划分为几块,一般分为新生代.老年代和永久代(对HotSpot虚拟机而言),这就是JVM的内存 ...

  9. jvm学习笔记一(垃圾回收算法)

    一:垃圾回收机制的原因 java中,当没有对象引用指向原先分配给某个对象的内存时候,该内存就成为了垃圾.JVM的一个系统级线程会自动释放该内存块.垃圾回收意味着程序不再需要的对象是"无用信息 ...

随机推荐

  1. 限制input只能输入金额(类似:100.00|100.9|100)

    $(".inputmoney").keyup(function () {    var reg = $(this).val().match(/\d+\.?\d{0,2}/);    ...

  2. 1208PHP基础

    PHP是一种创建动态交互性站点的强有力的服务器端脚本语言(后端.弱类型) 从地址栏直接寻找:localhost/路径/路径PHP语法:PHP脚本以<?php 开始,以?>结束; PHP文件 ...

  3. Jsonp跨域

    Jsonp.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  4. DelphiXE10.1项目中增加预编译的方法

    操作: 菜单选择Proceject->Options->Delphi Compilerz在Conditional Defines(第一行)中添加预编译标识.例:VCL代码:uses{$IF ...

  5. 0421 & SX2016

    山西省选...这个省...不算强吧...然而就是这么腊鸡题目还是wa得一无是处...怎么办啊怎么办啊...无处拯救青春和未来啊... T1: POI2004原题 BZOJ1524 n<=16.这 ...

  6. Windows中使用TortoiseGit提交项目到GitLab配置

    下文来给各位介绍Windows中使用TortoiseGit提交项目到GitLab配置过程,下在全部图片希望对各位带来方便面. Gitlab默认的配置推荐使用shell命令行与server端进行交互,作 ...

  7. 关于DOM对象与JQuery对象的那些事

    这个问题源自上一次的工作室讨论班,主题是"jQuery选择器的使用",在讨论班的结尾,我留了一个思考题:  jQuery获取到的对象和直接调用原生Javascript方法获得的对象 ...

  8. linux下QT程序输出乱码解决方法

    参考文章:http://blog.csdn.net/jiang1013nan/article/details/6667871 http://my.oschina.net/zjlaobusi/blog/ ...

  9. 关于node.js

    JS是一种脚本语言,它的本身并不能进行编译和执行,在最早的时期只是作为浏览器的脚本,只能够在浏览器中执行操作,也就是说JS必须依赖一个运行环境作为载体才能够执行. 而nodejs是基于chromeV8 ...

  10. 我的window10

    前言 这个一时半会写不完,也比较耗费时间,留着以后,每周更新一些新的技巧. 折腾了3天多时间的成果——>window10 的全新桌面,不比苹果差!不要说 windows 不能用 mac . 既然 ...