Jave garbage collection

1 篇文章 0 订阅
[b]什么是垃圾回收(garbage collection)[/b]
[b]Garbage Collection[/b] 是一种自动的存储器(内存)管理机制。当一个电脑上的动态存储器不再需要时,就应该予以释放,以让出存储器,这种存储器资源管理,称为垃圾回收。
垃圾回收的两个[b]基本原理[/b]:
[list]
[*]1、考虑某个对象的未来的程序运行中,将不会被访问。
[*]2、向这些对象要求归回存储器(内存)。[/list]
在Java中,开发人员无法直接在程序代码中清理内存,而是由垃圾回收器自动寻找不必要的垃圾对象,并且清理掉它们。[b]垃圾回收器会在下面两种假设成立的情况下被创建。[/b]
[list]
[*]1、大多数对象会很快变得不可达
[*]2、只有很少的由老对象指向新生对象的引用[/list]
[b]Stop-the-world [/b]会在任何一种gc的算法中发生,Stop-the-word 意味着JVM因为要执行GC而停止了应用程序的执行。当Stop-the-world发生时,除了GC所需要的线程以外,所有线程都处于等待状态,直到GC任务完成。[b]GC优化很多时候就是指减少stop-the-world发生的时间。[/b]
在Java程序中不能显式地分配和注销内存。有些人把相关的对象设置为null或者调用System.gc()来试图显式地清理内存。设置为null至少没有什么坏处,[b]但是调用System.gc()会显著地影响系统性能,必须彻底杜绝。[/b]
[b]Q:为什么要避免使用System.gc()来显式地清理内存?[/b]
[url]http://stackoverflow.com/questions/2414105/why-is-it-a-bad-practice-to-call-system-gc[/url]
[b]Q:如果老年代的对象需要引用一个新生代的对象,会发生什么呢?[/b]
为了解决这个问题,老年代中存在一个 “card table”,它是一个512 byte大小的块。所有老年代的对象指向新生代对象的引用都会被记录在这个表中。当针对新生代执行GC的时候,只需要查询card table来决定是否可以被收集,而不用查询整个老年代。这个card table由一个write barrier来管理。write barrier给GC带来了很大的性能提升,虽然由此可能带来了一些开销,但GC的整体时间被显著的减少。
[b]hotspot虚拟机可以为分为三个部分:[/b]
[list]
[*]1、Young Generation:
[*] 1、Eden 伊甸区存放新生对象
[*] 2、Survivor 存活区存放经过垃圾回收没有被清除的对象
[*] 3、semi-Spaces 和存活去做Copying collection
[*]2、Tenured(Old Generation):对象多次回收没有被清除,则移到该区块。
[*]3、Perm(Permanent Generation):存放加载的类型还有方法对象[/list]
[b]Young generation[/b]
绝大多数最新被创建的对象会被分配到这里,由于大部分对象在创建后会很快变得不可到达,所以很多对象被创建在新生代,然后消失。对象从这个区域消失的过程我们称之为“[b]minor GC[/b]”
[b]新生代[/b]是用来保存那些第一次被创建的对象,他可以被分为三个空间
[list]
[*]1、一个伊甸园空间(Eden)
[*]2、两个幸存者空间(Survivor)
[/list]
一共有三个空间,其中包含两个幸存者空间,每个空间的执行顺序如下:
[list]
[*]1、绝大多数刚刚被创建的对象会存放在伊甸园空间。
[*]2、在伊甸园空间执行了第一次GC之后,存活的对象被移动到其中一个幸存者空间
[*]3、此后,在伊甸园空间执行GC之后,存活的对象会被堆积在同一个幸存者空间。
[*]4、当一个幸存者空间饱和,还在存活的对象会被移动到另外一个幸存者空间,之后会清空已经饱和的那个幸存者空间?
[*]5、在以上的步骤中重复几次依然存活的对象,就会被移动到老年代。
[/list]
需要注意的是HotSpot虚拟机使用了[b]两种技术来加快内存分配[/b]。它们分别是“[b]bump-the-pointer[/b]”和“[b]TLABs(Thread-Local Allocation Buffers)[/b]”。
[b]Bump-the-pointer[/b]技术跟踪在伊甸园空间创建的最后一个对象。这个对象会被放在伊甸园空间的顶部。如果之后在需要创建对象,只需要检查伊甸园空间是否有足够的剩余空间。如果有足够的空间,对象就会被创建在伊甸园空间,并且被放置在顶部。这样一来,每次创建新的对象时,只需要检查最后被创建的对象。这将极大地加快内存分配速度。但是,若果我们在多线程的情况下,事情将截然不同。如果想要以线程安全的方式以多线程在伊甸园空间存储对象,不可避免的需要加锁,而这将极大地影响性能能。
[b]TLABs[/b]是HotSpot虚拟机针对这一问题的解决方案。该方案为每一个线程在伊甸园空间分配一块独享的空间,这样每个线程只访问他们自己的TLAB空间,再与bump-the-pointer技术结合可以在不加锁的情况下分配内存。
[b]Notice:对象刚刚被创建之后,是保存在伊甸园空间的。那些长期存活的对象经由幸存者空间转存在老年代空间。[/b]
[b]Old generation:[/b]
对象没有变得不可达,并且从新生代中存活下来,会被拷贝到这里。其所占用的空间要比新生代多。也正由于其相对较大的空间,发生在老年代上的GC要比新生代少得多。对象从老年代中的消失过程,我们称之为“[b]major GC”(full GC)[/b]。
老年代空间的GC事件基本上是在空间已满时发生,执行的过程根据GC类型不同而不同。
JDK7一共有5种GC类型:
[list]
[*]1、Serial GC
[*]2、Parallel GC
[*]3、Parallel Old GC
[*]4、Concurrent Mark&Sweep GC
[*]5、Garbage First(G1) GC
[/list]
其中Serial GC 不应该被用在服务器上。这种GC类型在单核CPU的桌面电脑时代就存在了。使用Serial GC会显著的降低应用的性能指标。
[b]1、Serial GC[/b]
在老年代空间中的GC采取称之为“mark-sweep-compact”的算法
[list]
[*]1、算法的第一步是标记老年代中依然存活的对象
[*]2、第二步,从头开始检查堆内存空间,并且只留下依然幸存的对象
[*]最后一步,从头开始,顺序地填满内存空间,并且将对内存空间分成两部分:一个保存着对象,另一个空着。
[/list]
[b]2、Parallel GC[/b]
Serail GC只使用一个线程执行GC,而parallel GC使用多个线程。因为parallel GC更高效。这种GC在内存充足以及多核的情况下会很有用。因为我们称之为“throughput GC”
[b]3、Parallel Old GC[/b]
与parallel GC相比,唯一的区别在于针对老年代的GC算法。Parallel Old GC分为三步:mark-summary-compaction 汇总步骤与情理的不同之处在于,其将依然幸存的对象分发到GC预先处理好的不同区域,算法相对清理来说略微复杂一点。
[b]4、CMC GC[/b]
这种GC比之前的各种算法都要复杂很多。第一步 initial mark。查找那些距离加载器最近的幸存对象。因为停顿的时间非常短暂。在之后的并行标记(concurrent mark)步骤,所有被幸存对象引用的对象会被确认是否已经被追踪和校验。这一点的不同之处在于,在标记的过程中,其他的线程依然在执行。在remark步骤,会再次检查那些并行标记步骤中增加或者删除的与幸存对象引用的对象。最后,在concurrent sweep步骤,转交垃圾回收过程处理。垃圾回收工作会在其他线程的执行过程中展开。一旦采取了这种GC类型,由GC导致的暂停时间会极其短暂。CMS GC 也被成为低延迟GC。它经常被用于在那些对于响应时间要求十分苛刻的应用之上。
当然,这种GC类型在拥有stop-the-world时间很短的有点的同时,也有如下缺点:
[list]
[*]1、它会比其他GC类型占用更多的内存和CPU
[*]2、默认情况下不支持压缩步骤
[/list]
[b]5、G1 GC[/b]
垃圾回收优先
每个对象被分配到不同的块,随着GC执行。当一个块区域装满之后,对象被分配到另一个区域,并执行GC。这中间不再有从新生代移动到老年代的三个步骤。这个类型是为了替代CMS GC为被创建的,因为CMS GC在长时间运作会产生很多问题。
[b]G1最大的好处是性能,他比我们在上面讨论过的任何一种GC都要块。[/b]
[b]性能考虑:[/b]
对于垃圾回收的性能,主要有两种度量方法:
[list]
[*]1、吞吐量。吞吐量是在一段足够长的时间中,没有花费在垃圾回收上的时间占总时间的百分比。吞吐量包含了花在空间费配上的时间(不过空间分配速度的调优一般是没有必要的)。
[*]2.延时。延时是由于等待垃圾回收而导致的程序没有响应的时间。
[/list]
[b]Heap的设置原则:[/b]
[list]
[*]1、除非遇到了时延问题,给虚拟机尽量多的内存。缺省尺寸(64MB)通常都太小了。
[*] 2、把-Xms 和 -Xmx 设置成相同的值,把最重要的尺寸决定从虚拟机收回来,从而增强可预见性。
[*] 3、 一般地,随着处理器数量的增加而增加内存,因为内存分配可以被并行化。
[/list]
[b]服务应用的设置准则是[/b]:
[list]
[*]● 首先确定可以提供给虚拟己的最大堆尺寸。然后根据性能需求来确定年轻代的尺寸,来找到最佳设置。
[*]● 注意:最大堆尺寸一定要小于系统中的内存数量,以防止过多的缺页错误和换页。
[*]● 如果总的堆尺寸是确定的,增加年轻代的尺寸就会减少年老代的尺寸。一定要保证年老代的尺寸,使之可以容纳所有在应用全程都要用到的活对象,并留有一定裕量(10-20%或更多)。
[*]● 依照上述年老代的约束:
[*]● 给年轻代分配足够的内存。
[*]● 如果有多个处理器,那么分配更多的内存给年轻代,因为内存分配可以并行化。
[/list]
[b]选择垃圾收集器[/b]:
除非你的应用有非常严酷的时延要求,那么就运行你的应用,并让系统自己选择垃圾收集器好了。如果有必要的话,就调整堆的大小来增进性能。如果性能仍然无法达到你的目标,那就按照如下设置来选择一个垃圾收集器。
[list]
[*]1. 如果应用的数据很少(大约不超过100MB),那么
[*]● 使用-XX:+UseSerialGC选择串行垃圾收集器。
[*]2.如果应用运行在单处理器系统中,并且没有什么时延要求,那么
[*]● 让虚拟机选择垃圾收集器,或者
[*]● 使用-XX:+UseSerialGC选择串行垃圾收集器。
[*]3.如果(a)程序峰值性能是第一位的,并且(b)没有时延要求,或时延要求是一两秒或更长,那么
[*]● 让虚拟机选择垃圾收集器,或者
[*]● 使用-XX:+UseParallelGC选择并行垃圾收集器,乃至(可选)通过 -XX:+UseParallelOldGC启用并行压缩。
[*]4.如果响应时间比总体吞吐量更为重要,并且垃圾收集时延需要控制在1秒以内,那么
[*]● select the concurrent collector with -XX:+UseConcMarkSweepGC. If only one or two processors are available, consider using incremental mode, described below.
[*]● 通过 -XX:+UseConcMarkSweepGC 参数启用并发垃圾收集器。进当你有一个或两个处理器可用的时候,考虑使用下文将要介绍的“增量模式”。
[/list]
这些指导意见仅仅是选择垃圾收集器的起点,因为性能依赖于堆的尺寸、应用中活数据的数量,以及处理器的数量和速度。时延参数对这些因素尤为敏感,所以,所谓的1秒门限值只是个大致数值:在很多硬件和数据量的组合情况下,并行垃圾收集器可能会导致停顿时间超过1秒;同样,在某些组合下,并发垃圾收集器也不能保证停顿小于1秒。
如果推荐的垃圾收集器没有达到期望的性能,首先应该尝试堆和代的尺寸,以期达到目标。如果仍然不成功的话,尝试更换一个垃圾收集器:使用并发垃圾收集器来减少停顿时间,使用并行垃圾收集器来增加多处理器系统中的吞吐量。
[b]Excessive GC Time and OutOfMemoryError(过多的gc时间以及内存溢出错误)[/b]
The parallel collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown. This feature is designed to prevent applications from running for an extended period of time while making little or no progress because the heap is too small. If necessary, this feature can be disabled by adding the option -XX:-UseGCOverheadLimit to the command line.
意思是说花费在垃圾收集上的时间太多,而释放的的空间却很少。就会抛出OutOfMemory。这个功能是用来防止堆太小导致程序长时间无法正常工作而设计的,如果必要,这个功能可以使用命令行参数
-XX:-UseGCOverheadLimit
来关闭。
[b]如何监控java 的garbage collection?[/b]
可以参考[url]http://www.cubrid.org/blog/dev-platform/how-to-monitor-java-garbage-collection/[/url]
[b]Is GC Tuning Required ir more precisely is GC tuning required for Java-based services?[/b]
Not always required.This means a Java-based system in operation has the following options and actions:
The memory size has bean specified using -Xms and -Xmx options.
The -server option is included.
Logs such as Timeout log are not left in the system
[b]In other words,if you have not set the memory size and too many Timeout logs are printed,you need to perform GC tuning on your system.[/b]
To control the GC performed by your system,you should,first, decrease the number of objects created.
"many a little makes a mickle."We need to take care of small things,or they will add up and become something big which is difficult to manage.
[list]
[*]We need to use and make StringBuilder or StringBuffer a way of life instead of String.
[*]And it is better to accumulate as few logs as possible.
[/list]
[b]If application memory usage improves after repeated tunings,you can start GC tuning.I classify the purposes of GC tuning into two:[/b]
[list]
[*]1、One is to minimize the number of objects passed to the old area;
[*]以最低数量的对象通过到old area
[*]you can adjust the size of the New area.
[*]2、and the other is to decrease F
[/list]ull GC execution time.
[b]另一个是减少Full GC的执行时间[/b]
The execution time of Full GC is relatively longer than that of Minor GC,Therefore,if it takes too much time to execute Full GC,timeout may occur in several connected parts.
* If you try to decrease the Old area size to decrease Full GC execution time, OutOfMemoryError may occur or the number of Full GCs may increase.
* Alternatively, if you try to decrease the number of Full GC by increasing the Old area size, the execution time will be increased.
[b]The basic principle of GC tuning is to apply the different GC options to two or more server and compare them,
The following table show options related to memory size among the GC options that can affect performance.[/b]
[list]
[*]Heap area size(-Xms Heap area size when starting JVM.-Xmx Maximum heal area size)
[*]New area size (-XX:NewRatio,-XX:NewSize,-XX:SurvivorRatio)
[/list]
[b]Procedure of GC Tuning:[/b]
[list]
[*]1、Monitoring GC status
[*]2、Deciding whether to tune GC after analysing the monitoring result
[*]3、Setting GC type/memory size
[*]4、Analyzing results
[*]5、If the result is satisfactory, apply the option to all servers and terminate GC tuning.
[*]
[/list]
[b]如何调整java的garbase collection?更加详细内容可参考[/b]
[url]http://www.cubrid.org/blog/dev-platform/how-to-tune-java-garbage-collection/[/url]
参考资料:
http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/
http://www.cubrid.org/blog/dev-platform/how-to-monitor-java-garbage-collection/
http://www.cubrid.org/blog/dev-platform/how-to-tune-java-garbage-collection/
http://chaoticjava.com/posts/how-does-garbage-collection-work/
http://stackoverflow.com/questions/1582209/java-garbage-collector-when-does-it-collect
http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值