2014-04-12 12:09 7226人阅读 评论(0) 收藏 举报
 分类:
J2SE(5) 

一.概述

java的最大好处是自动垃圾回收,这样就无需我们手动的释放对象空间了,但是也产生了相应的负效果,gc是需要时间和资源的,不好的gc会严重影响系统的系能,因此良好的gc是JVM的高性能的保证。JVM堆分为新生代,旧生代和年老代,新生代可用的gc方式有:串行gc(Serial Copying),并行回收gc(Parellel Scavenge),并行gc(ParNew),旧生代和年老代可用的gc方式有串行gc(Serial MSC),并行gc(Parallel MSC),并发gc(CMS)。

二.回收方式的选择

jvm有client和server两种模式,这两种模式的gc默认方式是不同的:

clien模式下,新生代选择的是串行gc,旧生代选择的是串行gc

server模式下,新生代选择的是并行回收gc,旧生代选择的是并行gc

一般来说我们系统应用选择有两种方式:吞吐量优先和暂停时间优先,对于吞吐量优先的采用server默认的并行gc方式,对于暂停时间优先的选用并发gc(CMS)方式。

三.CMS gc

CMS,全称Concurrent Low Pause Collector,是jdk1.4后期版本开始引入的新gc算法,在jdk5和jdk6中得到了进一步改进,它的主要适合场景是对响应时间的重要性需求大于对吞吐量的要求,能够承受垃圾回收线程和应用线程共享处理器资源,并且应用中存在比较多的长生命周期的对象的应用。CMS是用于对tenured generation的回收,也就是年老代的回收,目标是尽量减少应用的暂停时间,减少full gc发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代。在我们的应用中,因为有缓存的存在,并且对于响应时间也有比较高的要求,因此希望能尝试使用CMS来替代默认的server型JVM使用的并行收集器,以便获得更短的垃圾回收的暂停时间,提高程序的响应性。

    CMS并非没有暂停,而是用两次短暂停来替代串行标记整理算法的长暂停,它的收集周期是这样:

    初始标记(CMS-initial-mark) -> 并发标记(CMS-concurrent-mark) -> 重新标记(CMS-remark) -> 并发清除(CMS-concurrent-sweep) ->并发重设状态等待下次CMS的触发(CMS-concurrent-reset)

    其中的1,3两个步骤需要暂停所有的应用程序线程的。第一次暂停从root对象开始标记存活的对象,这个阶段称为初始标记;第二次暂停是在并发标记之后,暂停所有应用程序线程,重新标记并发标记阶段遗漏的对象(在并发标记阶段结束后对象状态的更新导致)。第一次暂停会比较短,第二次暂停通常会比较长,并且 remark这个阶段可以并行标记。

    而并发标记、并发清除、并发重设阶段的所谓并发,是指一个或者多个垃圾回收线程和应用程序线程并发地运行,垃圾回收线程不会暂停应用程序的执行,如果你有多于一个处理器,那么并发收集线程将与应用线程在不同的处理器上运行,显然,这样的开销就是会降低应用的吞吐量。Remark阶段的并行,是指暂停了所有应用程序后,启动一定数目的垃圾回收进程进行并行标记,此时的应用线程是暂停的。

四.full  gc

full gc是对新生代,旧生代,以及持久代的统一回收,由于是对整个空间的回收,因此比较慢,系统中应当尽量减少full gc的次数。

如下几种情况下会发生full gc:

《旧生代空间不足

《持久代空间不足

《CMS GC时出现了promotion failed和concurrent mode failure

《统计得到新生代minor gc时晋升到旧生代的平均大小小于旧生代剩余空间

《直接调用System.gc,可以DisableExplicitGC来禁止

《存在rmi调用时,默认会每分钟执行一次System.gc,可以通过-Dsun.rmi.dgc.server.gcInterval=3600000来设置大点的间隔。

五.示例

下面对如下的参数进行分析:

JAVA_OPTS="-server -Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m -XX:SurvivorRatio=4

-verbose:gc -Xloggc:$CATALINA_HOME/logs/gc.log -Djava.awt.headless=true -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Dsun.rmi.dgc.server.gcInterval=600000 -Dsun.rmi.dgc.client.gcInterval=600000

-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15"

-Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m

Xms,即为jvm启动时得JVM初始堆大小,Xmx为jvm的最大堆大小,xmn为新生代的大小,permsize为永久代的初始大小,MaxPermSize为永久代的最大空间。

-XX:SurvivorRatio=4

SurvivorRatio为新生代空间中的Eden区和救助空间Survivor区的大小比值,默认是32,也就是说Eden区是 Survivor区的32倍大小,要注意Survivo是有两个区的,因此Surivivor其实占整个young genertation的1/34。调小这个参数将增大survivor区,让对象尽量在survitor区呆长一点,减少进入年老代的对象。去掉救助空间的想法是让大部分不能马上回收的数据尽快进入年老代,加快年老代的回收频率,减少年老代暴涨的可能性,这个是通过将-XX:SurvivorRatio
设置成比较大的值(比如65536)来做到。

-verbose:gc -Xloggc:$CATALINA_HOME/logs/gc.log

将虚拟机每次垃圾回收的信息写到日志文件中,文件名由file指定,文件格式是平文件,内容和-verbose:gc输出内容相同。

-Djava.awt.headless=true

Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。

-XX:+PrintGCTimeStamps -XX:+PrintGCDetails

设置gc日志的格式

-Dsun.rmi.dgc.server.gcInterval=600000 -Dsun.rmi.dgc.client.gcInterval=600000

指定rmi调用时gc的时间间隔

-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15

采用并发gc方式,经过15次minor gc 后进入年老代

六.一些常见问题

1.为了避免Perm区满引起的full gc,建议开启CMS回收Perm区选项:

+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled


2.默认CMS是在tenured generation沾满68%的时候开始进行CMS收集,如果你的年老代增长不是那么快,并且希望降低CMS次数的话,可以适当调高此值:
-XX:CMSInitiatingOccupancyFraction=80

3.遇到两种fail引起full gc:Prommotion failed和Concurrent mode failed时:

Prommotion failed的日志输出大概是这样:

[ParNew (promotion failed): 320138K->320138K(353920K), 0.2365970 secs]42576.951: [CMS: 1139969K->1120688K(  166784K), 9.2214860 secs] 1458785K->1120688K(2520704K), 9.4584090 secs]

这个问题的产生是由于救助空间不够,从而向年老代转移对象,年老代没有足够的空间来容纳这些对象,导致一次full gc的产生。解决这个问题的办法有两种完全相反的倾向:增大救助空间、增大年老代或者去掉救助空间

Concurrent mode failed的日志大概是这样的

(concurrent mode failure): 1228795K->1228598K(1228800K), 7.6748280 secs] 1911483K->1681165K(1911488K), [CMS Perm : 225407K->225394K(262144K)], 7.6751800 secs]

问题的产生原因是由于CMS回收年老代的速度太慢,导致年老代在CMS完成前就被沾满,引起full gc,避免这个现象的产生就是调小-XX:CMSInitiatingOccupancyFraction参数的值,让CMS更早更频繁的触发,降低年老代被沾满的可能。

转载url:http://blog.163.com/mr_liuyong/blog/static/1234243762012066154911/

在JVM中,新生代和旧生代有何区别?GC的回收方式有几种?server和client有和区别?的更多相关文章

  1. Java虚拟机笔记(五):JVM中对象的分代

    为什么要分代 为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用, ...

  2. JVM的Server与Client运行模式区别与切换

    概述 JVM有两种运行模式Server与Client.两种模式的区别在于,Client模式启动速度较快,Server模式启动较慢:但是启动进入稳定期长期运行之后Server模式的程序运行速度比Clie ...

  3. JVM简介堆中新生代老年代浅析

    一.JVM内存结构由程序计数器.堆.栈.本地方法栈.方法区等部分组成.1)程序计数器 几乎不占有内存.用于取下一条执行的指令.2)堆 所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx ...

  4. 3、JVM中的对象

    1.对象的创建 A  a = new A() A:引用的类型 a::引用的名称 new A():创建一个A类对象 当创建一个对象时,具体创建过程是什么呢? (1)JVM遇到new的字节码指令后,检查类 ...

  5. JVM中内存回收深入分析,各种垃圾收集器

    JVM启动有两种模式,client和server 一般JVM启动时会根据主机情况分析选择采用那种模式启动 可发现是server模式 JVM中尤其需要关注的就是HEAP堆区 堆区分为新生代和老年代 新生 ...

  6. Stream入门及Stream在JVM中的线程表现

    继上次学习过Java8中的非常重要的Lambda表达式之后,接下来就要学习另一个也比较重要的知识啦,也就如标题所示:Stream,而它的学习是完全依赖于之前学习的Lambda表达式. 小实验引入: 这 ...

  7. JVM 的 工作原理,层次结构 以及 GC工作原理

    JVM Java 虚拟机 Java 虚拟机(Java virtual machine,JVM)是运行 Java 程序必不可少的机制.JVM实现了Java语言最重要的特征:即平台无关性.原理:编译后的 ...

  8. JVM中的堆的新生代、老年代、永久代详解

    JVM中的堆一般分为三大部分:新生代.老年代.永久代,其大致的占比如下:  一.新生代 新生代主要用来存放新生的对象.一般占据堆空间的1/3.在新生代中,保存着大量的刚刚创建的对象,但是大部分的对象都 ...

  9. JVM中的新生代、老年代和永生代

    1.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我 ...

随机推荐

  1. hadoop07---synchronized,lock

    synchronized 锁是jvm控制的,控制锁住的代码块只能有一个线程进入.线程执行完了锁自动释放,抛出异常jvm会释放锁. synchronized的缺陷 1.如果一个线程被阻塞了,其余的线程 ...

  2. 基于jQuery和Bootstrap的手风琴垂直菜单

    在线演示 本地下载

  3. 《网络攻防》Web安全基础实践

    20145224陈颢文 <网络攻防>Web安全基础实践 基础问题回答 SQL注入攻击原理,如何防御: 部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,黑客利用这个bug在数 ...

  4. 一个线程知识点, 一个MongoDB的知识点

    //WINForm窗体中切换前后台线程执行任务: protected void RunOnUI(Action action) { Invoke(action); } protected void Ru ...

  5. spring与memcached整合[转]

    1, 开始肯定是下载需要的文件了,这里就下载附件里的文件就好,我也是在网上down的,放这好找.然后我们安装一下Memcache服务器,找到解压的memcached-1.2.1-win32,启动cmd ...

  6. ixgbe RSS原理分析

    这个月,一直在搞ixgbe RSS,希望能使得收包均衡,结果没成功,但是对网卡的收包原理理解得更深入些. 1.网卡硬件通过网线或者光纤收包. 2.网卡的RSS功能根据网络五元组计算得到32bit的ha ...

  7. 字符串拆分split

    public static void main(String[] args) { String s = "A1B2C3D4E5F6G7H8"; String[] arr1 = s. ...

  8. C#抽象类和接口

    抽象类和接口有什么区别?有了抽象类为什么还要接口? 接口和抽象类的相同点是都不能实例化,不同点是接口中的方法都没有方法体,而抽象类则不然,除了抽象方法没有方法体外,其他方法都有方法体. 原因是:在C# ...

  9. HashMap和ConcurrentHashMap和HashTable的底层原理与剖析

    HashMap  可以允许key为null,value为null,但HashMap的是线程不安全的  HashMap 底层是数组 + 链表的数据结构 在jdk 1.7 中 map集合中的每一项都是一个 ...

  10. Treflection03_getFields_getField

    1. package reflectionZ; import java.lang.reflect.Constructor; import java.lang.reflect.Field; public ...