欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Sun JVM内存管理与Java虚拟机(JVM)垃圾回收器的工作机制 博客分类: OOM jvm虚拟机javasun工作

程序员文章站 2024-03-18 18:12:10
...

转自:http://dev.firnow.com/course/3_program/java/javajs/20100719/453020.html

内存管理和垃圾回收是JVM非常关键的点,对Java性能的剖析而言,了解内存管理和垃圾回收的基本策略非常重要。本篇对Sun JVM 6.0的内存管理和垃圾回收做大概的描述。

      1.内存管理
      在程序运行过程当中,会创建大量的对象,这些对象,大部分是短周期的对象,小部分是长周期的对象,对于短周期的对象,需要频繁地进行垃圾回收以保证无用对象尽早被释放掉,对于长周期对象,则不需要频率垃圾回收以确保无谓地垃圾扫描检测。为解决这种矛盾,Sun JVM的内存管理采用分代的策略。
      1)年轻代(Young Gen):年轻代主要存放新创建的对象,内存大小相对会比较小,垃圾回收会比较频繁。年轻代分成1个Eden Space和2个Suvivor Space(命名为A和B)

  • 当对象在堆创建时,将进入年轻代的Eden Space。
  • 垃圾回收器进行垃圾回收时,扫描Eden Space和A Suvivor Space,如果对象仍然存活,则复制到B Suvivor Space,如果B Suvivor Space已经满,则复制 Old Gen
  • 扫描A Suvivor Space时,如果对象已经经过了几次的扫描仍然存活,JVM认为其为一个Old对象,则将其移到Old Gen。
  • 扫描完毕后,JVM将Eden Space和A Suvivor Space清空,然后交换A和B的角色(即下次垃圾回收时会扫描Eden Space和BSuvivor Space。

      我们可以看到:Young Gen垃圾回收时,采用将存活对象复制到到空的Suvivor Space的方式来确保不存在内存碎片,采用空间换时间的方式来加速内存垃圾回收。
      2)年老代(Tenured Gen):年老代主要存放JVM认为比较old的对象(经过几次的Young Gen的垃圾回收后仍然存在),内存大小相对会比较大,垃圾回收也相对没有那么频繁(譬如可能几个小时一次)。年老代主要采用压缩的方式来避免内存碎片(将存活对象移动到内存片的一边),当然,有些垃圾回收器(譬如CMS垃圾回收器)出于效率的原因,可能会不进行压缩。
      3)持久代(Perm Gen):持久代主要存放类定义、字节码和常量等很少会变更的信息,关于这块的垃圾回收策略可以参考我的另一篇BLOG《Tomcat Context reloadabled 与 OutOfMemory(PermSpace) 》。
      Class data sharing (CDS)( http://java.sun.com/j2se/1.5.0/docs/guide/vm/class-data-sharing.html)是JDK5新引入的特性,采用在虚拟机之间共享一些class定义信息(bootstrapClassLoader加载的类)的方式提速JVM的启动和内存的占用,主要用于客户端,如果需要对类进行instrutment,最好把CDS关闭。(默认情况下,JVM的server模式会关闭CDS,client模式会开启CDS)

-Xshare:off
Disable class data sharing.
-Xshare:on
Require class data sharing to be enabled. If it could not be enabled for various reasons, print an error message and exit.
-Xshare:auto
The default; enable class data sharing whenever possible.

 

       我们通过JConsole截图看看上面这几个区的显示(下图),从左到右分别是EdenSpace、A Suvivor Space、Tenured Gen、Code Cache、Perm Gen(shared-wr)、Perm Gen(shared-ro)、Perm Gen
Sun JVM内存管理与Java虚拟机(JVM)垃圾回收器的工作机制 
            
    
    博客分类: OOM jvm虚拟机javasun工作
      2.垃圾回收策略
      评估垃圾回收策略的两个重要度量是:

  • 吞吐量(Throughput ):JVM花费在垃圾回收上的时间越长,则吞吐量越低
  • 暂停时间(Pause time):JVM垃圾回收过程当中有一个暂停期,在暂停期间,应用程序不能运行,暂停时间是暂停期的长度

      非常遗憾的是,一般这两个指标是相互冲突的,改善其中一个会影响到另外一个,根据情景的不同我们决定是优先考虑吞吐量还是暂停时间,对于需要实时响应的应用,我们需要优先考虑暂停时间,对于后台运行应用,我们需要优先考虑吞吐量。
      在考察各种垃圾回收器之前,我们需要了解一下几个重要的策略

  • 并行(Parallel):并行表示使用多个线程同时进行垃圾回收的工作,此策略一般会从同时改善暂停时间和吞吐量,在有多CPU内核的服务器上,这是基本上我们要使用的策略。
  • 并发(Concurrent):并行表示垃圾回收器的一些工作(譬如垃圾标记)与应用程序同时进行,这将更进一步缩短暂停时间,需要注意的是,同时垃圾回收器的复杂性会大大增大,基本上是会降低吞吐量,
  • 内存碎片处理:有不压缩、压缩和拷贝三种策略,从空间上讲,拷贝将花费更多的内存(譬如如上内存管理的Young Gen,需要维持一个额外的Suvivor空间),从时间上来讲,不压缩会减低创建对象时的内存分配效率,在垃圾回收上,拷贝策略会比压缩策略更高效。

      Sun JVM有4垃圾回收器:

  • Serial Collector:序列垃圾回收器,垃圾回收器对Young Gen和Tenured Gen都是使用单线的垃圾回收方式,对Young Gen,会使用拷贝策略避免内存碎片,对Old Gen,会使用压缩策略避免内存碎片。基本上,在对内核的服务器上应该避免使用这种方式。在JVM启动参数中使用-XX:+UseSerialGC启用Serial Collector。
  • Parallel Collector:并发垃圾回收器,垃圾回收器对Young Gen和Tenured Gen都是使用多线程并行垃圾回收的方式,对Young Gen,会使用拷贝策略避免内存碎片,对Old Gen,会使用压缩策略避免内存碎片。在JVM启动参数中使用-XX:+UseParallelGC启用Parallel Collector。
  • Parallel Compacting Collector:并行压缩垃圾回收器,与Parallel Collector垃圾回收类似,但对Tenured Gen会使用一种更有效的垃圾回收策略,此垃圾回收器在暂停时间上会更短。在JVM启动参数中使用-XX:+UseParallelOldGC启用Parallel Compacting Collector。
  • Concurrent Mark-Sweep (CMS) Collector:并发标志清除垃圾回收器,对Young Gen会使用与Parallel Collector同样的垃圾回收策略,对Tenured Gen,垃圾回收的垃圾标志线程与应用线程同时进行,而垃圾清除则需要暂停应用线程,但暂停时间会大大缩减,需要注意的是,由于垃圾回收过程更加复杂,会降低总体的吞吐量。

 

 

 

 

 

 

 

转自:http://blog.csdn.net/chen105315/archive/2009/06/12/4263528.aspx

回收机制

1、  在堆上分配对象的代价十分高昂,然而java的垃圾回收机制可以和其他语言从堆栈上分配空间的速度想媲美,但是,释放对上的存储空间也有开销;

2、  当它工作的时候,将一面回收空间,一面使堆中的对象紧凑排列。这样就尽量避免了页面错误。通过垃圾回收器对对象重新排列,实现了一种高速的、有限空间可供分配的堆模型;

3、  其他系统的垃圾回收机制:

a、  引用计数是一种简单但速度很慢的垃圾回收计数。每个对象都含有一个引用计数器,当有引用链接至对象时,引用计数加1,当引用离开作用于或者被设置为null时,引用计数减1。缺陷:如果兑现之间存在循环引用,就会出现麻烦。

b、  另一种思想:对任何“活”的对象,一定能够最终追溯到其存活在对战或静态存储区之中的引用。这个引用链条可能会穿过数个对象层次。由此,如果从堆栈和静态存储区开始,遍历所有的引用,就能找到所有的的“活”的对象。

4、  java的垃圾回收机制:

a、  停止—复制(stop-and-copy):先暂停程序的运行,然后将所有存活的对象从当前堆复制到另一个堆,没有复制的全部都是垃圾。当对象被复制到新堆时,它们是一个挨着一个的,紧凑的。效率很低:首先,得有两个堆空间占用率200%;其次,垃圾较少时,复制大量的活着的对象,是很大的浪费。

b、  标记—清扫(mark-and-sweep):从对战和静态存储区出发,遍历所有的引用,进而找出所有存活的对象,如果活着,就标记。只有全部标记完毕的时候,清理动作才开始。在清理的时候,没有标记的对象将会被释放,不会发生任何肤质动作。但是盛夏的对空间是不连续的,垃圾回收器要是希望得到连续空间的话,就得重新整理剩下的对象。

c、  注意:“停止—复制”的意思是这种垃圾回收动作不是在后台进行的;相反,垃圾回收动作发生的同时,程序将会被暂停。有人将垃圾回收视为低优先级的后台进程,而事实上并不是这样,当可用内存数量比较低的时候,Sun版本的垃圾回收器就会暂停运行程序。同样,“标记-清扫”工作也必须在程序暂停的情况下才能进行。

d、  java虚拟机中,内存分配是以较大的块为单位的。每个块内都用相应的代数(generation count)来记录它是否还存活。代数随着引用的次数而增加。垃圾回收器将对上次回收动作之后的新分配的块进行整理。这对处理大量短命的临时对象很有帮助。垃圾回收器会定期进行完整的清理动作——大型对象仍然不会被复制(只是代数增加),内涵小型对象的那些块则被复制并整理。Java虚拟机会进行监视,如果所有对象都很稳定,垃圾回收器的效率降低的话,就切换到“标记—清扫”方式;同样,java虚拟机会追踪“标记—清扫”的效果,要是堆空间出现很多碎片,就会切换到“停止—复制”方式。这就是“自适应”技术。

 

总结:Java垃圾回收器是一种“自适应的、分代的、停止—复制、标记-清扫”式的垃圾回收器