GC应用整理 TBD

来源:互联网 发布:淘宝主图最好是多少kb 编辑:程序博客网 时间:2024/06/03 17:40

http://www.cnblogs.com/zuoxiaolong/category/508918.html   TBD


full gc(即major gc,CMS包含两次,CMS遇到错误触发单线程MSC 算一次)触发条件,可设置 old 区 占用比例,eg 到了80% 则触发,还可以在cms中设定几次full gc后进行 compact. 如果old区空间不够,会停下来 采用serial gc去先回收一次 old区域.  但实际一般old不到比例,就发生full gc了,因为 promotion guarantee 担保old能够承受young中送过来的object(minor 转 full) refert to http://www.newsmth.net/nForum/#!article/Java/299246

minor何时被触发? 1.young 不够了就触发了,为什么会触发那么频繁,因为方法里的local变量 朝生夕灭的特性。 (可以试试 stopmain线程,minorgc 就步频繁了),minor很快 如下.

minor的并行是stoptheworld之所以很快是因为,认为活着的对象很少,parallel复制算法 所耗的时间就少,如果 eden中都是活的 也会慢的

http://www.open-open.com/lib/view/open1429883238291.html


为什么 要搞eden survivor1 survivor2,

survivor1

1 和 2轮流作为 复制算法的 to space, eg 第二轮中间时 ,eden有对象,s1有对象, 在young进行回收的时候,就回去 用复制算法 parallel 去将s1 和 eden的活对象 放到s2


永久区 会被回收吗?  会

年轻代和年老代是存储动态产生的对象。永久带主要是存储的是java的类信息,包括解析得到的方法、属性、字段等等。永久带基本不参与垃圾回收

现在问题出现了:

 [Full GC (System) 3601.118: [CMS: 187025K->113740K(5242880K), 0.8019600 secs] 1129480K->113740K(7340032K), [CMS Perm : 57763K->50540K(131072K)], 0.8024830 secs] [Times: user=0.80 sys=0.00, real=0.80 secs] 

1,当出现Fullgc后,明显看到perm己发生过回收,且系统中会出现反射调用失败的一些提示信息。

2,在配制cms回收时,看到Perm开启CMS回收Perm区选项:
+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled


reference————————

周志明的《深入理解Java虚拟机》P51对于类的卸载有这样的描述:
类需要同时满足下面3个条件才能算是“无用的类”:

□该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
□加载该类的ClassLoader已经被回收。
□该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。


转载请注明出处:http://blog.sina.com.cn/s/blog_68158ebf0100wp83.html

一、Java内存的构成
    先上一个官方javadocument里的图:
我对Java内存的认识(原创)
    由上图可知,整块区域分为YoungGeneration、Tenured Generation、Permanent Generation。

详细解释一下Young区:
    Young区又分为:Eden、SurvivorSpace。
    Survivor Space又分为 ToSurvivor、 From Survivor,如下图所示:

我对Java内存的认识(原创)


Java内存分为 堆内存(heap)和 Permanent区。
1、Java堆内存(heap):
    --是 JVM 用于分配 Java对象的内存,包含活动对象和不可用对象 
    --堆大小通常是在服务器启动时使用 java命令中的 –Xms(最小) –Xmx(最大)标志来定义。 
2、Permanent区:
    --指内存的永久保存区域
    --是Sun JDK和HPJDK用来加载类(class)和Meta信息的专门的内存区
   --这个区域不归属Java堆内存(heap)范围
   --Class在被Loader时就会被放到此,如果Java应用很大,例如类(class)很多,那么建议增大这个区域的大小来满足加载这些类的内存需求
    --通过–XX:PermSize=***M–XX:MaxPermSize=***M调整

这里还有一个本地内存的概念:
·本地内存(native memory): 
    --是 JVM用于其内部操作的本地内存(非Java内存) 
    --JNI 代码和第三方本地模块(例如,本地JDBC 驱动程序)也使用本地内存 
   --最大本地内存大小取决于以下因素:操作系统进程内存大小限制、已经指定用于 Java 堆的内存

也就是说,整个物理机的内存可以说由以下部分构成:
物理内存 = Java 内存 + 本地内存 + 操作系统保留的内存


二、垃圾回收(Garbage Collection,GC)

1、为什么要垃圾回收
   --JVM自动检测和释放不再使用的内存。 
    --Java 运行时JVM会执行GC,这样程序员不再需要显式释放对象。 

2、垃圾回收(GC)的分类
    --Minor GC
    --Full GC

3、垃圾回收(GC)的产生过程
    1)新生成的对象在Eden区完成内存分配
    2)当Eden区满了,再创建对象,会因为申请不到空间,触发minorGC,进行young(eden+1survivor)区的垃圾回收。(为什么是eden+1survivor:两个survivor中始终有一个survivor是空的,空的那个被标记成ToSurvivor)
    3)minorGC时,Eden不能被回收的对象被放入到空的survivor(也就是放到ToSurvivor,同时Eden肯定会被清空),另一个survivor(FromSurvivor)里不能被GC回收的对象也会被放入这个survivor(ToSurvivor),始终保证一个survivor是空的。(MinorGC完成之后,To Survivor 和 FromSurvivor的标记互换)
    4)当做第3步的时候,如果发现存放对象的那个survivor满了,则这些对象被copy到old区,或者survivor区没有满,但是有些对象已经足够Old(通过XX:MaxTenuringThreshold参数来设置),也被放入Old区
    5)当Old区被放满的之后,进行完整的垃圾回收,即 Full GC
     6)FullGC时,整理的是Old Generation里的对象,把存活的对象放入到Permanent Generation里。

4、垃圾回收的回收器
  --串行(–XX:+UseSerialGC )
    Out ofBox算法,年轻代串行复制,年老代串行标记整理,主要用于桌面应用

  --并行(–XX:+UseParallelGC )
    年轻代暂停应用程序,多个垃圾收集线程并行的复制收集,年老代暂停应用程序,与串行收集器一样,单垃圾收集线程标记整理。JDK6.0启用该算法后,默认启用了-XX:+UseParallelOldGC,性能大为提高

  --并发(Concurrent Low Pause Collector)(–XX:+UseConcMarkSweepGC )
    启用该参数,默认启用了-XX:+UseParNewGC;简单的说,并发是指用户线程与垃圾收集线程并发,程序在继续运行,而垃圾收集程序运行于其他CPU上。


三、Java内存的调优参数
-Xmx1024m:
    设置JVM最大可用内存为1024M。

-Xms1024m:
   设置JVM促使内存为1024M。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。

-Xmn512m:
   设置年轻代大小为512M。(持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。)

-Xss128k:
   设置每个线程的堆栈大小。这个值可以根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成。

-XX:NewRatio=4
   设置年轻代(包括Eden和两个Survivor区)与年老代的比值(总的大小是Xms的值)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5。
    举个例子,-Xms 设置为 1024m,-Xmx也设置为 1024m的情况下:
      ·年轻代= 1024M/5 = 204.8M
      ·年老代= 1024M/5*4 = 819.2M
    如果-Xms和-Xmx的值设置的不一样,可以添加-XX:MinHeapFreeRatio=<minimum> 和-XX:MaxHeapFreeRatio=<maximum>参数,使内存的大小能够在 大于 -Xms 和 小于 -Xmx之间的范围内自动调整,所以内存中会有Virtual的空间(我是这样理解的,不是太清楚,这里需要大家指教)
英文原文如下:http://java.sun.com/docs/hotspot/gc1.4.2/#3.Sizing the Generations|outline
    By default, the virtualmachine grows or shrinks the heap at each collection to try to keepthe proportion of free space to live objects at each collectionwithin a specific range. This target range is set as a percentageby the parameters-XX:MinHeapFreeRatio=<minimum> and-XX:MaxHeapFreeRatio=<maximum>, andthe total size is bounded below by -Xms and above by -Xmx .

-XX:SurvivorRatio=4:
   设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6

-XX:MaxPermSize=16m:
    设置持久代大小为16m。

-XX:MaxTenuringThreshold=0:
   设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。

总结如下图:
我对Java内存的认识(原创)


四、内存分配中会出现的错误
关于内存最常见的错误应该是这两个:
  --内存溢出 Out Of Memory(OOM)
  --内存泄露 Memory Leak (ML)
 
1、内存溢出
   内存溢出发生在这种状况下:Java内存完成Minor GC 之后想要把还存活的对象放到 Old区里,但是这时Old区 已经满了,同时 Permanent区也已经放不下存活的对象。这时就会产生 OOM错误。

2、内存泄露
   在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是有被引用的,即在有向树形图中,存在树枝通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。
   找到一个例子:
  这里引用一个常看到的例子,在下面的代码中,循环申请Object对象,并将所申请的对象放入一个Vector中,如果仅仅释放对象本身,但因为Vector仍然引用该对象,所以这个对象对GC来说是不可回收的。因此,如果对象加入到Vector后,还必须从Vector中删除,最简单的方法就是将Vector对象设置为null。
  1. Vector new Vector(10);     
  2. for (int 1100i++)     
  3.     
  4.  Object new Object();     
  5.  v.add(o);     
  6.  o null    
  7. }//此时,所有的Object对象都没有被释放,因为变量v引用这些对象。     

实际上这些对象已经是无用的,但还被引用,GC就无能为力了(事实上GC认为它还有用),这一点是导致内存泄漏最重要的原因。”

3、补充一个:PermGen space Error
    因为 GC不会在主程序运行期对PermGen space进行清理,所以如果应用中有很CLASS需要Load的话,就很可能出现PermGenspace错误。
    另外如果WEBAPP下使用了大量的第三方jar, 其大小超过了 jvm 默认的大小那么也会产生此错误信息了。


五、总结
  上面4点的内容可以跟下面这个图来进行融合:
我对Java内存的认识(原创)



0 0
原创粉丝点击