﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Fantasy's World-随笔分类-摘抄</title><link>http://www.blogjava.net/FinalFantasy/category/3675.html</link><description>世界的小世界，我的大世界^_^</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 05:38:41 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 05:38:41 GMT</pubDate><ttl>60</ttl><item><title>Java回收机制分析</title><link>http://www.blogjava.net/FinalFantasy/archive/2005/12/26/25474.html</link><dc:creator>FinalFantasy</dc:creator><author>FinalFantasy</author><pubDate>Mon, 26 Dec 2005 09:46:00 GMT</pubDate><guid>http://www.blogjava.net/FinalFantasy/archive/2005/12/26/25474.html</guid><wfw:comment>http://www.blogjava.net/FinalFantasy/comments/25474.html</wfw:comment><comments>http://www.blogjava.net/FinalFantasy/archive/2005/12/26/25474.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/FinalFantasy/comments/commentRss/25474.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/FinalFantasy/services/trackbacks/25474.html</trackback:ping><description><![CDATA[这个文档是老师给我们看的，看了之后收获不少，帖出来让大家也看看：）
<HR>

<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-pagination: widow-orphan"><B><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">引言</SPAN></B><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma"> <SPAN lang=EN-US><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">Java</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">的堆是一个运行时数据区<SPAN lang=EN-US>,</SPAN>类的实例<SPAN lang=EN-US>(</SPAN>对象<SPAN lang=EN-US>)</SPAN>从中分配空间。<SPAN lang=EN-US>Java</SPAN>虚拟机<SPAN lang=EN-US>(JVM)</SPAN>的堆中储存着正在运行的应用程序所建立的所有对象，这些对象通过<SPAN lang=EN-US>new</SPAN>、<SPAN lang=EN-US>newarray</SPAN>、<SPAN lang=EN-US>anewarray</SPAN>和<SPAN lang=EN-US>multianewarray</SPAN>等指令建立，但是它们不需要程序代码来显式地释放。一般来说，堆的是由垃圾回收 来负责的，尽管<SPAN lang=EN-US>JVM</SPAN>规范并不要求特殊的垃圾回收技术，甚至根本就不需要垃圾回收，但是由于内存的有限性，<SPAN lang=EN-US>JVM</SPAN>在实现的时候都有一个由垃圾回收所管理的堆。垃圾回收是一种动态存储管理技术，它自动地释放不再被程序引用的对象，按照特定的垃圾收集算法来实现资源自动回收的功能。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-pagination: widow-orphan"><B><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">垃圾收集的意义<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-pagination: widow-orphan"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">在<SPAN lang=EN-US>C++</SPAN>中，对象所占的内存在程序结束运行之前一直被占用，在明确释放之前不能分配给其它对象；而在<SPAN lang=EN-US>Java</SPAN>中，当没有对象引用指向原先分配给某个对象的内存时，该内存便成为垃圾。<SPAN lang=EN-US>JVM</SPAN>的一个系统级线程会自动释放该内存块。垃圾收集意味着程序不再需要的对象是<SPAN lang=EN-US>"</SPAN>无用信息<SPAN lang=EN-US>"</SPAN>，这些信息将被丢弃。当一个对象不再被引用的时候，内存回收它占领的空间，以便空间被后来的新对象使用。事实上，除了释放没用的对象，垃圾收集也可以清除内存记录碎片。由于创建对象和垃圾收集器释放丢弃对象所占的内存空间，内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆的一端，<SPAN lang=EN-US>JVM</SPAN>将整理出的内存分配给新的对象。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-pagination: widow-orphan"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">垃圾收集能自动释放内存空间，减轻编程的负担。这使<SPAN lang=EN-US>Java </SPAN>虚拟机具有一些优点。首先，它能使编程效率提高。在没有垃圾收集机制的时候，可能要花许多时间来解决一个难懂的存储器问题。在用<SPAN lang=EN-US>Java</SPAN>语言编程的时候，靠垃圾收集机制可大大缩短时间。其次是它保护程序的完整性<SPAN lang=EN-US>, </SPAN>垃圾收集是<SPAN lang=EN-US>Java</SPAN>语言安全性策略的一个重要部份。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-pagination: widow-orphan"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">垃圾收集的一个潜在的缺点是它的开销影响程序性能。<SPAN lang=EN-US>Java</SPAN>虚拟机必须追踪运行程序中有用的对象<SPAN lang=EN-US>, </SPAN>而且最终释放没用的对象。这一个过程需要花费处理器的时间。其次垃圾收集算法的不完备性，早先采用的某些垃圾收集算法就不能保证<SPAN lang=EN-US>100%</SPAN>收集到所有的废弃内存。当然随着垃圾收集算法的不断改进以及软硬件运行效率的不断提升，这些问题都可以迎刃而解。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-pagination: widow-orphan"><B><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">垃圾收集的算法分析<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">Java</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">语言规范没有明确地说明<SPAN lang=EN-US>JVM</SPAN>使用哪种垃圾回收算法，但是任何一种垃圾收集算法一般要做<SPAN lang=EN-US>2</SPAN>件基本的事情：（<SPAN lang=EN-US>1</SPAN>）发现无用信息对象；（<SPAN lang=EN-US>2</SPAN>）回收被无用对象占用的内存空间，使该空间可被程序再次使用。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-pagination: widow-orphan"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">大多数垃圾回收算法使用了根集<SPAN lang=EN-US>(root set)</SPAN>这个概念；所谓根集就量正在执行的<SPAN lang=EN-US>Java</SPAN>程序可以访问的引用变量的集合<SPAN lang=EN-US>(</SPAN>包括局部变量、参数、类变量<SPAN lang=EN-US>)</SPAN>，程序可以使用引用变量访问对象的属性和调用对象的方法。垃圾收集首选需要确定从根开始哪些是可达的和哪些是不可达的，从根集可达的对象都是活动对象，它们不能作为垃圾被回收，这也包括从根集间接可达的对象。而根集通过任意路径不可达的对象符合垃圾收集的条件，应该被回收。下面介绍几个常用的算法。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 27pt; TEXT-INDENT: -18pt; mso-pagination: widow-orphan; mso-list: l0 level1 lfo1; tab-stops: list 27.0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><SPAN style="mso-list: Ignore">1、<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp; </SPAN></SPAN></SPAN><SPAN style="COLOR: red; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">引用计数法</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">(Reference Counting Collector)<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-pagination: widow-orphan"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">引用计数法是唯一没有使用根集的垃圾回收的法，该算法使用引用计数器来区分存活对象和不再使用的对象。一般来说，堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时，引用计数器置为<SPAN lang=EN-US>1</SPAN>。当对象被赋给任意变量时，引用计数器每次加<SPAN lang=EN-US>1</SPAN>当对象出了作用域后<SPAN lang=EN-US>(</SPAN>该对象丢弃不再使用<SPAN lang=EN-US>)</SPAN>，引用计数器减<SPAN lang=EN-US>1</SPAN>，一旦引用计数器为<SPAN lang=EN-US>0</SPAN>，对象就满足了垃圾收集的条件。</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 17.95pt; mso-pagination: widow-orphan"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">基于引用计数器的垃圾收集器运行较快，不会长时间中断程序执行，适宜地必须 实时运行的程序。但引用计数器增加了程序执行的开销，因为每次对象赋给新的变量，计数器加<SPAN lang=EN-US>1</SPAN>，而每次现有对象出了作用域生，计数器减<SPAN lang=EN-US>1</SPAN>。</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 17.95pt; TEXT-INDENT: -17.95pt; mso-pagination: widow-orphan; mso-char-indent-count: -1.71"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">2</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">、<SPAN lang=EN-US style="COLOR: red">tracing</SPAN><SPAN style="COLOR: red">算法</SPAN><SPAN lang=EN-US>(Tracing Collector)</SPAN></SPAN><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 17.95pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">tracing</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">算法是为了解决引用计数法的问题而提出，它使用了根集的概念。基于<SPAN lang=EN-US>tracing</SPAN>算法的垃圾收集器从根集开始扫描，识别出哪些对象可达，哪些对象不可达，并用某种方式标记可达对象，例如对每个可达对象设置一个或多个位。在扫描识别过程中，基于<SPAN lang=EN-US>tracing</SPAN>算法的垃圾收集也称为标记和清除<SPAN lang=EN-US>(mark-and-sweep)</SPAN>垃圾收集器<SPAN lang=EN-US>.<o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">3</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">、<SPAN lang=EN-US style="COLOR: red">compacting</SPAN>算法<SPAN lang=EN-US>(Compacting Collector)<o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-pagination: widow-orphan"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">为了解决堆碎片问题，基于<SPAN lang=EN-US>tracing</SPAN>的垃圾回收吸收了<SPAN lang=EN-US>Compacting</SPAN>算法的思想，在清除的过程中，算法将所有的对象移到堆的一端，堆的另一端就变成了一个相邻的空闲内存区，收集器会对它移动的所有对象的所有引用进行更新，使得这些引用在新的位置能识别原来 的对象。在基于<SPAN lang=EN-US>Compacting</SPAN>算法的收集器的实现中，一般增加句柄和句柄表。　　<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">4</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">、<SPAN lang=EN-US style="COLOR: red">copying</SPAN><SPAN style="COLOR: red">算法</SPAN><SPAN lang=EN-US>(Coping Collector)<o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-pagination: widow-orphan"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成 一个对象 面和多个空闲面， 程序从对象面为对象分配空间，当对象满了，基于<SPAN lang=EN-US>coping</SPAN>算法的垃圾 收集就从根集中扫描活动对象，并将每个 活动对象复制到空闲面<SPAN lang=EN-US>(</SPAN>使得活动对象所占的内存之间没有空闲洞<SPAN lang=EN-US>)</SPAN>，这样空闲面变成了对象面，原来的对象面变成了空闲面，程序会在新的对象面中分配内存。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-pagination: widow-orphan"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">一种典型的基于<SPAN lang=EN-US>coping</SPAN>算法的垃圾回收是<SPAN lang=EN-US>stop-and-copy</SPAN>算法，它将堆分成对象面和空闲区域面，在对象面与空闲区域面的切换过程中，程序暂停执行。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">5</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">、<SPAN lang=EN-US style="COLOR: red">generation</SPAN>算法<SPAN lang=EN-US>(Generational Collector)<BR></SPAN>　　<SPAN lang=EN-US>stop-and-copy</SPAN>垃圾收集器的一个缺陷是收集器必须复制所有的活动对象，这增加了程序等待时间，这是<SPAN lang=EN-US>coping</SPAN>算法低效的原因。在程序设计中有这样的规律：多数对象存在的时间比较短，少数的存在时间比较长。因此，<SPAN lang=EN-US>generation</SPAN>算法将堆分成两个或多个，每个子堆作为对象的一代<SPAN lang=EN-US>(generation)</SPAN>。由于多数对象存在的时间比较短，随着程序丢弃不使用的对象，垃圾收集器将从最年轻的子堆中收集这些对象。在分代式的垃圾收集器运行后，上次运行存活下来的对象移到下一最高代的子堆中，由于老一代的子堆不会经常被回收，因而节省了时间。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">6</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">、<SPAN lang=EN-US style="COLOR: red">adaptive</SPAN>算法<SPAN lang=EN-US>(Adaptive Collector)<o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-pagination: widow-orphan"><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">在特定的情况下，一些垃圾收集算法会优于其它算法。基于<SPAN lang=EN-US>Adaptive</SPAN>算法的垃圾收集器就是监控当前堆的使用情况，并将选择适当算法的垃圾收集器。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-pagination: widow-orphan"><B><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">透视<SPAN lang=EN-US>Java</SPAN>垃圾回收</SPAN></B><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma"><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">1</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">、命令行参数透视垃圾收集器的运行<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">2</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">、使用<SPAN lang=EN-US>System.gc()</SPAN>可以不管<SPAN lang=EN-US>JVM</SPAN>使用的是哪一种垃圾回收的算法，都可以请求<SPAN lang=EN-US>Java</SPAN>的垃圾回收。在命令行中有一个参数<SPAN lang=EN-US>-verbosegc</SPAN>可以查看<SPAN lang=EN-US>Java</SPAN>使用的堆内存的情况，它的格式如下：<SPAN lang=EN-US><BR><BR><SPAN style="COLOR: red">java -verbosegc classfile</SPAN><BR><BR></SPAN>　　可以看个例子：</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">class TestGC <BR>{<BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">　<SPAN lang=EN-US>public static void main(String[] args) <BR></SPAN>　<SPAN lang=EN-US>{<BR></SPAN>　　<SPAN lang=EN-US>new TestGC();<BR></SPAN>　　<SPAN lang=EN-US>System.gc();<BR></SPAN>　　<SPAN lang=EN-US>System.runFinalization();<BR></SPAN>　<SPAN lang=EN-US>}<BR>}<o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma"><BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">　　在这个例子中，一个新的对象被创建，由于它没有使用，所以该对象迅速地变为可达，程序编译后，执行命令：<SPAN lang=EN-US> java -verbosegc TestGC </SPAN>后结果为：<SPAN lang=EN-US><BR><BR>[Full GC 168K-&gt;97K(1984K), 0.0253873 secs]<BR><BR></SPAN>　　机器的环境为，<SPAN lang=EN-US>Windows 2000 + JDK<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year="1899">1.3.1</st1:chsdate>,</SPAN>箭头前后的数据<SPAN lang=EN-US>168K</SPAN>和<SPAN lang=EN-US>97K</SPAN>分别表示垃圾收集<SPAN lang=EN-US>GC</SPAN>前后所有存活对象使用的内存容量，说明有<SPAN lang=EN-US>168K-97K=71K</SPAN>的对象容量被回收，括号内的数据<SPAN lang=EN-US>1984K</SPAN>为堆内存的总容量，收集所需要的时间是<SPAN lang=EN-US>0.0253873</SPAN>秒（这个时间在每次执行的时候会有所不同）。<SPAN lang=EN-US><BR><BR></SPAN>　　<SPAN lang=EN-US>2</SPAN>、<SPAN lang=EN-US>finalize</SPAN>方法透视垃圾收集器的运行<SPAN lang=EN-US><BR><BR></SPAN>　　在<SPAN lang=EN-US>JVM</SPAN>垃圾收集器收集一个对象之前 ，一般要求程序调用适当的方法释放资源，但在没有明确释放资源的情况下，<SPAN lang=EN-US>Java</SPAN>提供了缺省机制来终止化该对象心释放资源，这个方法就是<SPAN lang=EN-US>finalize</SPAN>（）。它的原型为：<SPAN lang=EN-US><BR><BR>protected void finalize() throws Throwable<BR><BR></SPAN>　　在<SPAN lang=EN-US>finalize()</SPAN>方法返回之后，对象消失，垃圾收集开始执行。原型中的<SPAN lang=EN-US>throws Throwable</SPAN>表示它可以抛出任何类型的异常。<SPAN lang=EN-US><BR><BR></SPAN>　　之所以要使用<SPAN lang=EN-US>finalize()</SPAN>，是由于有时需要采取与<SPAN lang=EN-US>Java</SPAN>的普通方法不同的一种方法，通过分配内存来做一些具有<SPAN lang=EN-US>C</SPAN>风格的事情。这主要可以通过<SPAN lang=EN-US>"</SPAN>固有方法<SPAN lang=EN-US>"</SPAN>来进行，它是从<SPAN lang=EN-US>Java</SPAN>里调用非<SPAN lang=EN-US>Java</SPAN>方法的一种方式。<SPAN lang=EN-US>C</SPAN>和<SPAN lang=EN-US>C++</SPAN>是目前唯一获得固有方法支持的语言。但由于它们能调用通过其他语言编写的子程序，所以能够有效地调用任何东西。在非<SPAN lang=EN-US>Java</SPAN>代码内部，也许能调用<SPAN lang=EN-US>C</SPAN>的<SPAN lang=EN-US>malloc()</SPAN>系列函数，用它分配存储空间。而且除非调用了<SPAN lang=EN-US>free()</SPAN>，否则存储空间不会得到释放，从而造成内存<SPAN lang=EN-US>"</SPAN>漏洞<SPAN lang=EN-US>"</SPAN>的出现。当然，<SPAN lang=EN-US>free()</SPAN>是一个<SPAN lang=EN-US>C</SPAN>和<SPAN lang=EN-US>C++</SPAN>函数，所以我们需要在<SPAN lang=EN-US>finalize()</SPAN>内部的一个固有方法中调用它。也就是说我们不能过多地使用<SPAN lang=EN-US>finalize()</SPAN>，它并不是进行普通清除工作的理想场所。<SPAN lang=EN-US><BR><BR></SPAN>　　在普通的清除工作中，为清除一个对象，那个对象的用户必须在希望进行清除的地点调用一个清除方法。这与<SPAN lang=EN-US>C++"</SPAN>破坏器<SPAN lang=EN-US>"</SPAN>的概念稍有抵触。在<SPAN lang=EN-US>C++</SPAN>中，所有对象都会破坏（清除）。或者换句话说，所有对象都<SPAN lang=EN-US>"</SPAN>应该<SPAN lang=EN-US>"</SPAN>破坏。若将<SPAN lang=EN-US>C++</SPAN>对象创建成一个本地对象，比如在堆栈中创建（在<SPAN lang=EN-US>Java</SPAN>中是不可能的），那么清除或破坏工作就会在<SPAN lang=EN-US>"</SPAN>结束花括号<SPAN lang=EN-US>"</SPAN>所代表的、创建这个对象的作用域的末尾进行。若对象是用<SPAN lang=EN-US>new</SPAN>创建的（类似于<SPAN lang=EN-US>Java</SPAN>），那么当程序员调用<SPAN lang=EN-US>C++</SPAN>的<SPAN lang=EN-US>delete</SPAN>命令时（<SPAN lang=EN-US>Java</SPAN>没有这个命令），就会调用相应的破坏器。若程序员忘记了，那么永远不会调用破坏器，我们最终得到的将是一个内存<SPAN lang=EN-US>"</SPAN>漏洞<SPAN lang=EN-US>"</SPAN>，另外还包括对象的其他部分永远不会得到清除。<SPAN lang=EN-US><BR><BR></SPAN>　　相反，<SPAN lang=EN-US>Java</SPAN>不允许我们创建本地（局部）对象<SPAN lang=EN-US>--</SPAN>无论如何都要使用<SPAN lang=EN-US>new</SPAN>。但在<SPAN lang=EN-US>Java</SPAN>中，没有<SPAN lang=EN-US>"delete"</SPAN>命令来释放对象，因为垃圾收集器会帮助我们自动释放存储空间。所以如果站在比较简化的立场，我们可以说正是由于存在垃圾收集机制，所以<SPAN lang=EN-US>Java</SPAN>没有破坏器。然而，随着以后学习的深入，就会知道垃圾收集器的存在并不能完全消除对破坏器的需要，或者说不能消除对破坏器代表的那种机制的需要（而且绝对不能直接调用<SPAN lang=EN-US>finalize()</SPAN>，所以应尽量避免用它）。若希望执行除释放存储空间之外的其他某种形式的清除工作，仍然必须调用<SPAN lang=EN-US>Java</SPAN>中的一个方法。它等价于<SPAN lang=EN-US>C++</SPAN>的破坏器，只是没后者方便。<SPAN lang=EN-US><BR><BR></SPAN>　　下面这个例子向大家展示了垃圾收集所经历的过程，并对前面的陈述进行了总结。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-pagination: widow-orphan"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">class Chair {<BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">　<SPAN lang=EN-US>static boolean gcrun = false;<BR></SPAN>　<SPAN lang=EN-US>static boolean f = false;<BR></SPAN>　<SPAN lang=EN-US>static int created = 0;<BR></SPAN>　<SPAN lang=EN-US>static int finalized = 0;<BR></SPAN>　<SPAN lang=EN-US>int i;<BR></SPAN>　<SPAN lang=EN-US>Chair() {<BR></SPAN>　　<SPAN lang=EN-US>i = ++created;<BR></SPAN>　　<SPAN lang=EN-US>if(created == 47) <BR></SPAN>　　　<SPAN lang=EN-US>System.out.println("Created 47");<BR></SPAN>　<SPAN lang=EN-US>}<BR></SPAN>　<SPAN lang=EN-US>protected void finalize() {<BR></SPAN>　　<SPAN lang=EN-US>if(!gcrun) {<BR></SPAN>　　　<SPAN lang=EN-US>gcrun = true;<BR></SPAN>　　　<SPAN lang=EN-US>System.out.println("Beginning to finalize after " + created + " Chairs have been created");<BR></SPAN>　　<SPAN lang=EN-US>}<BR></SPAN>　　<SPAN lang=EN-US>if(i == 47) {<BR></SPAN>　　　<SPAN lang=EN-US>System.out.println("Finalizing Chair #47, " +"Setting flag to stop Chair creation");<BR></SPAN>　　　<SPAN lang=EN-US>f = true;<BR></SPAN>　　<SPAN lang=EN-US>}<BR></SPAN>　　<SPAN lang=EN-US>finalized++;<BR></SPAN>　　<SPAN lang=EN-US>if(finalized &gt;= created)<BR></SPAN>　　　<SPAN lang=EN-US>System.out.println("All " + finalized + " finalized");<BR></SPAN>　<SPAN lang=EN-US>}<BR>}<BR><BR>public class Garbage {<BR></SPAN>　<SPAN lang=EN-US>public static void main(String[] args) {<BR></SPAN>　　<SPAN lang=EN-US>if(args.length == 0) {<BR></SPAN>　　　<SPAN lang=EN-US>System.err.println("Usage: \n" + "java Garbage before\n or:\n" + "java Garbage after");<BR></SPAN>　　　<SPAN lang=EN-US>return;<BR></SPAN>　　<SPAN lang=EN-US>}<BR></SPAN>　　<SPAN lang=EN-US>while(!Chair.f) {<BR></SPAN>　　　<SPAN lang=EN-US>new Chair();<BR></SPAN>　　　<SPAN lang=EN-US>new String("To take up space");<BR></SPAN>　　<SPAN lang=EN-US>}<BR></SPAN>　　<SPAN lang=EN-US>System.out.println("After all Chairs have been created:\n" + "total created = " + Chair.created +<BR>", total finalized = " + Chair.finalized);<BR></SPAN>　　<SPAN lang=EN-US>if(args[0].equals("before")) {<BR></SPAN>　　　　<SPAN lang=EN-US>System.out.println("gc():");<BR></SPAN>　　　　<SPAN lang=EN-US>System.gc();<BR></SPAN>　　　　<SPAN lang=EN-US>System.out.println("runFinalization():");<BR></SPAN>　　　　<SPAN lang=EN-US>System.runFinalization();<BR></SPAN>　　<SPAN lang=EN-US>}<BR></SPAN>　　<SPAN lang=EN-US>System.out.println("bye!");<BR></SPAN>　　<SPAN lang=EN-US>if(args[0].equals("after"))<BR></SPAN>　　　<SPAN lang=EN-US>System.runFinalizersOnExit(true);<BR></SPAN>　<SPAN lang=EN-US>}<BR>}<o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma"><BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma">　　上面这个程序创建了许多<SPAN lang=EN-US>Chair</SPAN>对象，而且在垃圾收集器开始运行后的某些时候，程序会停止创建<SPAN lang=EN-US>Chair</SPAN>。由于垃圾收集器可能在任何时间运行，所以我们不能准确知道它在何时启动。因此，程序用一个名为<SPAN lang=EN-US>gcrun</SPAN>的标记来指出垃圾收集器是否已经开始运行。利用第二个标记<SPAN lang=EN-US>f</SPAN>，<SPAN lang=EN-US>Chair</SPAN>可告诉<SPAN lang=EN-US>main()</SPAN>它应停止对象的生成。这两个标记都是在<SPAN lang=EN-US>finalize()</SPAN>内部设置的，它调用于垃圾收集期间。另两个<SPAN lang=EN-US>static</SPAN>变量<SPAN lang=EN-US>--created</SPAN>以及<SPAN lang=EN-US>finalized--</SPAN>分别用于跟踪已创建的对象数量以及垃圾收集器已进行完收尾工作的对象数量。最后，每个<SPAN lang=EN-US>Chair</SPAN>都有它自己的（非<SPAN lang=EN-US>static</SPAN>）<SPAN lang=EN-US>int i</SPAN>，所以能跟踪了解它具体的编号是多少。编号为<SPAN lang=EN-US>47</SPAN>的<SPAN lang=EN-US>Chair</SPAN>进行完收尾工作后，标记会设为<SPAN lang=EN-US>true</SPAN>，最终结束<SPAN lang=EN-US>Chair</SPAN>对象的创建过程。（关于这个例子的更具体的分析和说明请参看《<SPAN lang=EN-US>Java</SPAN>编程思想》的第四章）<SPAN lang=EN-US><BR><BR></SPAN>　　<B>关于垃圾收集的几点补充</B><SPAN lang=EN-US><BR><BR></SPAN>　　经过上述的说明，可以发现垃圾回收有以下的几个特点：<SPAN lang=EN-US><BR><BR></SPAN>　　（<SPAN lang=EN-US>1</SPAN>）垃圾收集发生的不可预知性：由于实现了不同的垃圾收集算法和采用了不同的收集机制，所以它有可能是定时发生，有可能是当出现系统空闲<SPAN lang=EN-US>CPU</SPAN>资源时发生，也有可能是和原始的垃圾收集一样，等到内存消耗出现极限时发生，这与垃圾收集器的选择和具体的设置都有关系。<SPAN lang=EN-US><BR><BR></SPAN>　　（<SPAN lang=EN-US>2</SPAN>）垃圾收集的精确性：主要包括<SPAN lang=EN-US>2 </SPAN>个方面：（<SPAN lang=EN-US>a</SPAN>）垃圾收集器能够精确标记活着的对象；（<SPAN lang=EN-US>b</SPAN>）垃圾收集器能够精确地定位对象之间的引用关系。前者是完全地回收所有废弃对象的前提，否则就可能造成内存泄漏。而后者则是实现归并和复制等算法的必要条件。所有不可达对象都能够可靠地得到回收，所有对象都能够重新分配，允许对象的复制和对象内存的缩并，这样就有效地防止内存的支离破碎。（<SPAN lang=EN-US>3</SPAN>）现在有许多种不同的垃圾收集器，每种有其算法且其表现各异，既有当垃圾收集开始时就停止应用程序的运行，又有当垃圾收集开始时也允许应用程序的线程运行，还有在同一时间垃圾收集多线程运行。<SPAN lang=EN-US><BR><BR></SPAN>　　（<SPAN lang=EN-US>4</SPAN>）垃圾收集的实现和具体的<SPAN lang=EN-US>JVM </SPAN>以及<SPAN lang=EN-US>JVM</SPAN>的内存模型有非常紧密的关系。不同的<SPAN lang=EN-US>JVM </SPAN>可能采用不同的垃圾收集，而<SPAN lang=EN-US>JVM </SPAN>的内存模型决定着该<SPAN lang=EN-US>JVM</SPAN>可以采用哪些类型垃圾收集。现在，<SPAN lang=EN-US>HotSpot </SPAN>系列<SPAN lang=EN-US>JVM</SPAN>中的内存系统都采用先进的面向对象的框架设计，这使得该系列<SPAN lang=EN-US>JVM</SPAN>都可以采用最先进的垃圾收集。<SPAN lang=EN-US><BR><BR></SPAN>　　（<SPAN lang=EN-US>5</SPAN>）随着技术的发展，现代垃圾收集技术提供许多可选的垃圾收集器，而且在配置每种收集器的时候又可以设置不同的参数，这就使得根据不同的应用环境获得最优的应用性能成为可能。<SPAN lang=EN-US><BR><BR></SPAN>　　针对以上特点，我们在使用的时候要注意：<SPAN lang=EN-US><BR><BR></SPAN>　　（<SPAN lang=EN-US>1</SPAN>）不要试图去假定垃圾收集发生的时间，这一切都是未知的。比如，方法中的一个临时对象在方法调用完毕后就变成了无用对象，这个时候它的内存就可以被释放。<SPAN lang=EN-US><BR><BR></SPAN>　　（<SPAN lang=EN-US>2</SPAN>）<SPAN lang=EN-US>Java</SPAN>中提供了一些和垃圾收集打交道的类，而且提供了一种强行执行垃圾收集的方法<SPAN lang=EN-US>--</SPAN>调用<SPAN lang=EN-US>System.gc()</SPAN>，但这同样是个不确定的方法。<SPAN lang=EN-US>Java </SPAN>中并不保证每次调用该方法就一定能够启动垃圾收集，它只不过会向<SPAN lang=EN-US>JVM</SPAN>发出这样一个申请，到底是否真正执行垃圾收集，一切都是个未知数。<SPAN lang=EN-US><BR><BR></SPAN>　　（<SPAN lang=EN-US>3</SPAN>）挑选适合自己的垃圾收集器。一般来说，如果系统没有特殊和苛刻的性能要求，可以采用<SPAN lang=EN-US>JVM</SPAN>的缺省选项。否则可以考虑使用有针对性的垃圾收集器，比如增量收集器就比较适合实时性要求较高的系统之中。系统具有较高的配置，有比较多的闲置资源，可以考虑使用并行标记<SPAN lang=EN-US>/</SPAN>清除收集器。<SPAN lang=EN-US><BR><BR></SPAN>　　（<SPAN lang=EN-US>4</SPAN>）关键的也是难把握的问题是内存泄漏。良好的编程习惯和严谨的编程态度永远是最重要的，不要让自己的一个小错误导致内存出现大漏洞。<SPAN lang=EN-US><BR><BR></SPAN>　　（<SPAN lang=EN-US>5</SPAN>）尽早释放无用对象的引用。大多数程序员在使用临时变量的时候，都是让引用变量在退出活动域<SPAN lang=EN-US>(scope)</SPAN>后，自动设置为<SPAN lang=EN-US>null</SPAN>，暗示垃圾收集器来收集该对象，还必须注意该引用的对象是否被监听，如果有，则要去掉监听器，然后再赋空值。<SPAN lang=EN-US><BR><BR></SPAN>　　<B>结束语</B><SPAN lang=EN-US><BR><BR></SPAN>　　一般来说，<SPAN lang=EN-US>Java</SPAN>开发人员可以不重视<SPAN lang=EN-US>JVM</SPAN>中堆内存的分配和垃圾处理收集，但是，充分理解<SPAN lang=EN-US>Java</SPAN>的这一特性可以让我们更有效地利用资源。同时要注意<SPAN lang=EN-US>finalize()</SPAN>方法是<SPAN lang=EN-US>Java</SPAN>的缺省机制，有时为确保对象资源的明确释放，可以编写自己的<SPAN lang=EN-US>finalize</SPAN>方法。<SPAN lang=EN-US><o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-bidi-font-family: Tahoma"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt"><o:p>&nbsp;</o:p></SPAN></P><img src ="http://www.blogjava.net/FinalFantasy/aggbug/25474.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/FinalFantasy/" target="_blank">FinalFantasy</a> 2005-12-26 17:46 <a href="http://www.blogjava.net/FinalFantasy/archive/2005/12/26/25474.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>