`
wzping
  • 浏览: 103068 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论
阅读更多
GC与JVM堆
引言
    这些天一直在和兄弟们做通信的模型测试,在环境中为了模拟多客户端访问,经常使用大量的线程,在线程中用到了很多对象,占据了不少存储空间,GC(garbage collector)而引发的问题浮出水面,虽然测试已经结束,有些问题还没弄清楚,于是我找了很多文章想看个究竟,现在把所看文章的精华摘抄和自己的所得写下来,扔块破砖,希望能砸出个玉矿来:)。
JVM堆相关知识
    为什么先说JVM堆?
    JVM的堆是Java对象的活动空间,程序中的类的对象从中分配空间,其存储着正在运行着的应用程序用到的所有对象。这些对象的建立方式就是那些new一类的操作,当对象无用后,是GC来负责这个无用的对象(地球人都知道)。

GC是如何去回收这些对象的,当中会有什么影响?这跟JVM堆本身的构造是分不开的。
JVM堆的结构如下:

JVM堆

    新域:存储所有新成生的对象

  
    旧域:新域中的对象,经过了一定次数的GC循环后,被移入旧域
=================================================================

永久域:存储类和方法对象,从配置的角度看,这个域是独立的,不包括在JVM堆内。默认为4M。



    GC 是通过JVM上的一个或一组进程来实现,GC在运行时同样会占用堆空间,也占用cpu,而且,GC运行时,是对JVM堆进行操作,所以,应用程序会停止运行,也就是说GC运行时,不仅会消耗一定的资源,而且会影响应用程序的运行。当应用比较小而简单时,GC的影响可以忽略,但对于大型而复杂的应用,GC的处理机制就显得非常重要了。

水是有源的,树是有根的,GC有影响也是有原因的!(王大鹏 语录)
GC浅谈
    GC的工作目的很明确:在堆中,找到已经无用的对象,并把这些对象占用的空间收回使其可以重新利用。

    Java 规范没有对GC进行明确的定义,所以不同的JVM,其GC的实现方法就不太相同,在<<Java编程思想>>那块砖头中讲述了一种方法:对活动对象和无用对象使用计数器,如果这个对象被引用一次,则其对应的计数器加1,如果对象不在作用域中使用,计数器减1,当计数器为0,这个对象就可以被回收了。
这个方法的优点是针对每个对象做操作,不会大规模地进行对堆的操作,所以不会长时间中断应用程序,缺点也明显,它必须实时运行,所以程序开销就大了,唉,鱼和熊掌不能兼得。

    大多数垃圾回收的算法思路都是一致的:把所有对象组成一个集合,或可以理解为树状结构,从树根开始找,只要可以找到的都是活动对象,如果找不到,这个对象就是凋零的昨日黄花,应该被回收了。

    从资料上查到的这种算法如下:
l    tracing算法(tracing collector): 从根集开始扫描,识别出哪些对象可达,哪些对象不可达,并用某种方式标记可达对象。基于tracing算法的垃圾收集也称为标记和清除 (mark-and-sweep)垃圾收集器。
l    compacting 算法(compacting collector):在清除的过程中,将所有的对象移到堆的一端,堆的另一端就变成了一个相邻的空闲内存区,收集器会对它移动的所有对象的所有引用进行更新,使得这些引用 在新的位置能识别原来的对象。一般增加句柄和句柄表。
l    coping算法 (coping collector):该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成一个对象面和多个空闲面,程序从对象面为对象分配空间,当对象满了,基于 coping算法的垃圾收集就从根集中扫描活动对象,并将每个活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲洞),这样空闲面变成了对象面,原来的对象面变成了空闲面,程序会在新的对象面中分配内存。
l    generation算法 (generational collector):在程序设计中有这样的规律:多数对象存在的时间比较短,少数的存在时间比较长。因此,generation算法将堆分成两个或多个,每个子堆作为对象的一代 (generation)。由于多数对象存在的时间比较短,随着程序丢弃不使用的对象,垃圾收集器将从最年轻的子堆中收集这些对象。在分代式的垃圾收集器运行后,上次运行存活下来的对象移到下一最高代的子堆中,由于老一代的子堆不会经常被回收,因而节省了时间。
l    adaptive算法(adaptive collector):在特定的情况下,一些垃圾收集算法会优于其它算法。基于adaptive算法的垃圾收集器就是监控当前堆的使用情况,并将选择适当算法的垃圾收集器。

了解了GC的算法,也熟悉了JVM堆的构造,看看两者的关系。
GC与JVM堆的关系
在sun 的文档说明中,对JVM堆的新域,是采用coping算法,新域会被分为3个部分
l    第一个部分叫Eden。  (伊甸园??可能是因为亚当和夏娃是人类最早的活动对象?)
l    另两个部分称为辅助生存空间(幼儿园),我这里一个称为A空间,一个称为B空间。

对于新生成的对象,都放在Eden中;当Eden充满时(小孩太多了),GC将开始工作,首先停止应用程序的运行,开始收集垃圾,把所有可找到的对象都复制到A空间中,一旦当A空间充满,GC就把在A空间中可找到的对象都复制到B空间中(会覆盖原有的存储对象),当B空间满的时间,GC就把在B空间中可找到的对象都复制到A空间中,AB在这个过程中互换角色,那位客官说了:拷来拷去,烦不烦啊?什么时候是头?您别急,在活动对象经过一定次数的GC操作后,这些活动对象就会被放到旧域中。对于这些活动对象,新域的幼儿园生活结束了。

新域为什么要这么折腾?
起初在这块我也很迷糊,又查了些资料,原来是这样:应用程序生成的绝大部分对象都是短命的,copying算法最理想的状态是,所有移出Eden的对象都会被收集,因为这些都是短命鬼,经过一定次数的GC后应该被收集,那么移入到旧域的对象都是长命的,这样可以防止AB空间的来回复制影响应用程序。
实际上这种理想状态是很难达到的,应用程序中不可避免地存在长命的对象,copying算法的发明者要这些对象都尽量放在新域中,以保证小范围的复制,压缩旧域的开销可比新域中的复制大得多(旧域在下面说)。

对于旧域,采用的是tracing算法的一种,称为标记-清除-压缩收集器,注意,这有一个压缩,这是个开销挺大的操作。所以,新域中采用copying算法是有道理的。
搜索到的结果与建议
    从上面的推导可以得出很多结论,下面是前辈的经验总结与自已的认识
l    JVM堆的大小决定了GC的运行时间。如果JVM堆的大小超过一定的限度,那么GC的运行时间会很长。
l    对象生存的时间越长,GC需要的回收时间也越长,影响了回收速度。
l    大多数对象都是短命的,所以,如果能让这些对象的生存期在GC的一次运行周期内,wonderful!
l    应用程序中,建立与释放对象的速度决定了垃圾收集的频率。
l    如果GC一次运行周期超过3-5秒,这会很影响应用程序的运行,如果可以,应该减少JVM堆的大小了。
l    前辈经验之谈:通常情况下,JVM堆的大小应为物理内存的80%。

在编程中应该注意到的:
l    大家都知道GC的执行时间是不确定的,调用System.gc()也无法确定GC什么时候执行,这个函数只是向JVM发一个申请,究竟什么时候做,还得老大JVM决定。
l    JVM 也不能保证Finalize方法一定会被调用,而且对finalize方法的使用要注意,GC为了支持finalize,对覆盖这个函数的对象作很多附加的工作,同时,它要让在finalize运行之后,将要释放的对象变成可访问到的(树状结构中),GC还要再检查一次这个对象是否变成可访问到的,如果一来,GC的性能就打了折扣了。另外,finalize不同于Java其它的普通方法,它是通过类似于c语言的通过分配内存来干活的,相当于在 finalize()内部调用了类似于full()的c函数。所以,资料上不推荐用finalize进行普通清除。
l    查了N多的资料,JVM的缺省选项在通常情况下是最优的。
l    尽早释放无用的对象,如果对象无用了,就将其设置为null,这就告诉GC,这个对象你可以回收了。但要注意,如果对象是很复杂的类型(树,图等),或有监听器,那就要小心了。

附录
下面的地址是讲JVM的一些选项设置,用于设置JVM堆的参数和输入GC调试信息等。
官方设置JVM的选项说明网页
http://java.sun.com/docs/hotspot/VMOptions.html
一个sun公司的人收集的JVM的选项
http://blogs.sun.com/roller/resources/watt/jvm-options-list.html


Magneto_cn
2005-9-15
分享到:
评论

相关推荐

    JVM垃圾回收机制与GC性能调优

    本文主要探讨JVM堆内存的结构和GC的工作原理,以及如何进行性能调优。 JVM堆是Java应用程序的主要内存区域,用于存储所有类实例和数组。它分为三个主要区域:新域(Young Generation)、旧域(Old Generation)和...

    jvm和gc详解及调优

    5. **GC调优**:包括如何分析GC日志,理解GC停顿(Stop-the-World)事件,以及如何通过调整JVM参数来改善系统性能,如设置堆大小、新生代与老年代的比例、存活代的晋升策略等。 6. **性能监控与诊断工具**:如...

    深入理解JVM&G1; GC

    开发者可以通过调整JVM参数,如设置年轻代与老年代的比例、分配的Region数量、暂停时间目标等,来优化G1 GC的行为,从而达到更好的系统性能。 总之,《深入理解JVM & G1 GC》这本书为读者提供了理解JVM内存模型和G1...

    jvm gc

    5. **JVM调优**:通过调整JVM参数,可以控制GC的行为,例如设置堆大小、新生代和老年代的比例、GC策略等。常用的JVM参数有`-Xms`, `-Xmx`, `-Xmn`, `-XX:NewRatio`, `-XX:SurvivorRatio`, `-XX:+UseConcMarkSweepGC`...

    jvm 参数及gc详解

    Java虚拟机(JVM)是Java程序运行的基础,它的配置参数和垃圾收集(GC)机制对于优化应用程序性能至关重要。本文将深入探讨JVM参数及其与Java垃圾收集相关的知识。 一、JVM参数详解 JVM参数可以分为三类:启动参数...

    JAVA GC 与 JVM调优1

    GC主要针对的是Java堆内存中的对象,这里的对象是由Java栈中的引用指向的。Java栈中每个线程都有一个独立的虚拟机栈,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。当对象不再有任何引用链(GC Roots)...

    JVM_GC调优

    ### JVM_GC调优详解 #### 一、JVM体系结构概览 Java虚拟机(JVM)作为Java程序的运行环境,其内部结构复杂且高效。为了更好地理解JVM_GC调优,我们首先来了解一下JVM的基本组成部分。 1. **类装载器子系统(Class ...

    JVM体系结构与GC调优

    **JVM体系结构与GC调优** Java虚拟机(JVM)是Java应用程序的核心组成部分,它为Java程序提供了一个运行时环境。理解JVM的体系结构对于优化Java应用的性能至关重要,尤其是垃圾收集(Garbage Collection, GC)的...

    深入理解JVM & G1 GC

    《深入理解JVM & G1 GC》这篇文章和相关压缩包文件主要聚焦于Java虚拟机(JVM)的内存管理,特别是垃圾收集器(GC)的优化,特别是G1(Garbage-First)垃圾收集器的深度解析。下面将详细阐述JVM、GC的基本概念,...

    java应用JVM的GC频率观察方法

    Java 应用程序的JVM(Java虚拟机)性能优化是一个关键领域,而垃圾收集(GC)作为内存管理的一部分,其频率对系统性能有直接影响。GC的频率反映了系统的内存使用情况和健康状况。通常,GC分为两种主要类型:Scavenge...

    深入JVM内核—原理、诊断与优化视频教程-4.GC算法与种类

    本教程——“深入JVM内核—原理、诊断与优化视频教程”着重讲解了JVM的内部机制,特别是关于垃圾收集(Garbage Collection, GC)的算法和种类,这对于理解和提升Java应用性能至关重要。 一、JVM内存模型 首先,...

    JVM中[堆]的所有内容-pdf

    Java虚拟机(JVM)的堆内存是Java应用程序中存储对象实例的主要区域,它在JVM启动时被创建,并且其大小可以根据需求进行调整。堆内存可以被所有线程共享,其中包含了年轻代、老年代以及(在某些版本中)永久代或元...

    jvm gc jvm调优 查看工具

    1. 内存配置:通过JVM启动参数如-Xms、-Xmx设置堆内存大小,-XX:NewRatio调整新生代和老年代的比例,-XX:SurvivorRatio设置Eden和Survivor区的比例,以及-XX:MaxMetaspaceSize(或-XX:MaxPermSize)设定元空间或永久...

    JVM_GC_-调优总结.pdf

    - **JVM堆(heap)空间的大小**: - 堆空间设置较大时,完全GC执行较耗时,但执行频率较低。 - 堆空间设置恰好满足应用内存需求时,完全GC执行较快,但执行更频繁。 #### 二、Heap(堆)概述 **2.1 堆空间定义** -...

    Jvm1.8_GC.mmap

    GC:Gabage Collection,指JVM堆内存区域的垃圾回收 Minor GC:年轻代垃圾回收,所有的Majar GC都会触发进程暂停,只是这个实际很短 Major GC:也叫Full GC,年老代垃圾回收 年轻代和年老代的GC策略是不...

    思维导图-详细了解JVM和GC过程

    调整JVM参数可以优化GC性能,如`-Xms`和`-Xmx`设定堆大小,`-XX:NewRatio`设定新生代与老年代的比例,`-XX:SurvivorRatio`设定Survivor区与Eden区的比例,`-XX:+UseConcMarkSweepGC`启用CMS收集器等。 理解JVM内存...

    mac mat jvm gc 内存分析

    通过调整JVM参数,例如设置堆大小、新生代与老年代的比例、GC策略等,可以有效地避免内存溢出和性能瓶颈。 在进行内存分析时,MAT的几个关键功能不容忽视: - Leak Suspects报告:MAT会自动分析heap dump,提供...

    jvm-full-gc调优-jvm-full-gc.zip

    5. **JVM参数调整**:通过设置JVM参数可以影响GC行为,如`-Xms`和`-Xmx`控制堆内存大小,`-XX:NewRatio`设置新生代与老年代的比例,`-XX:MaxPermSize`或`-XX:MetaspaceSize`控制方法区大小,`-XX:+...

Global site tag (gtag.js) - Google Analytics