﻿<?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-记忆好很大程度决定能力!-文章分类-JAVA知识</title><link>http://www.blogjava.net/microlab4321/category/24883.html</link><description>适时总结是一种很好的彌补方法!</description><language>zh-cn</language><lastBuildDate>Sat, 18 Aug 2007 16:46:59 GMT</lastBuildDate><pubDate>Sat, 18 Aug 2007 16:46:59 GMT</pubDate><ttl>60</ttl><item><title>jsp-java-mysql字符集统一 </title><link>http://www.blogjava.net/microlab4321/articles/137616.html</link><dc:creator>冬天出走的猪</dc:creator><author>冬天出走的猪</author><pubDate>Fri, 17 Aug 2007 08:31:00 GMT</pubDate><guid>http://www.blogjava.net/microlab4321/articles/137616.html</guid><wfw:comment>http://www.blogjava.net/microlab4321/comments/137616.html</wfw:comment><comments>http://www.blogjava.net/microlab4321/articles/137616.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/microlab4321/comments/commentRss/137616.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/microlab4321/services/trackbacks/137616.html</trackback:ping><description><![CDATA[1、在jsp中，字符集由&lt;%@ page language="java" contentType="text/html;charset=GBK"%&gt;来指定，如果处理中文，需指定为gbk。所以提交的数据全部都使用gbk编码；<br>2、在java中，从jsp提交过来的数据是gbk编码的，而java默认的处理方式是使用ISO-8859-1编码，所以若在java中能显示jsp提交过来的gbk编码方式的数据，就要进行一个转换：将gbk转换为ISO-8859-1，这样数据就可正常显示。<br>3、如果要将jsp提交的数据经过java后台处理，然后放入数据库中，就又多了一个数据编码方式：数据库的数据编码方式。以mysql为例，默认字符集为latin，所以若将gbk的数据放入，必然出现乱码，所以首先应改变数据库的编码方式为gbk。<br><br>综上，简单的设置方法如下：<br><br>jsp&nbsp;(gbk)&nbsp;&nbsp;&nbsp;&nbsp; ----&gt;&nbsp;&nbsp;&nbsp;&nbsp; java(ISO-8859-1)&nbsp; -------&gt; mysql(gbk)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 转换<br>这样设置之后，还有一种情况会出现乱码：当你在jsp端提交一个id号，然后在java处理端通过id号得到数据库中的gbk（汉字）数据，这是就会出现乱码，因为java处理的是ISO-8859-1，你在java到mysql中有了一个ISO-8859-1到gbk的转换，而这些数据本身就是ISO-8859-1,所以转换后就出现问题了。<br>解决办法：将在java中处理的gbk数据转换为ISO-8859-1即可。<br><br>总之：在jsp，java，mysql三者之间的编码方式必须统一，不能错误的转换或者不转换。 
<img src ="http://www.blogjava.net/microlab4321/aggbug/137616.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/microlab4321/" target="_blank">冬天出走的猪</a> 2007-08-17 16:31 <a href="http://www.blogjava.net/microlab4321/articles/137616.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hashtable和HashMap的区别 </title><link>http://www.blogjava.net/microlab4321/articles/137298.html</link><dc:creator>冬天出走的猪</dc:creator><author>冬天出走的猪</author><pubDate>Thu, 16 Aug 2007 07:58:00 GMT</pubDate><guid>http://www.blogjava.net/microlab4321/articles/137298.html</guid><wfw:comment>http://www.blogjava.net/microlab4321/comments/137298.html</wfw:comment><comments>http://www.blogjava.net/microlab4321/articles/137298.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/microlab4321/comments/commentRss/137298.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/microlab4321/services/trackbacks/137298.html</trackback:ping><description><![CDATA[1.Hashtable是Dictionary的子类，HashMap是Map接口的一个实现类；<br><br>2.Hashtable中的方法是同步的，而HashMap中的方法在缺省情况下是非同步的。即是说，在多线程应用程序中，不用专门的操作就安全地可以使用Hashtable了；而对于HashMap，则需要额外的同步机制。但HashMap的同步问题可通过Collections的一个静态方法得到解决：<br><strong>Map Collections.synchronizedMap(Map m)</strong><br>这个方法返回一个同步的Map，这个Map封装了底层的HashMap的所有方法，使得底层的HashMap即使是在多线程的环境中也是安全的。<br><br>3.在HashMap中，null可以作为键，这样的键只有一个；可以有一个或多个键所对应的值为null。当get()方法返回null值时，即可以表示HashMap中没有该键，也可以表示该键所对应的值为null。因此，在HashMap中不能由get()方法来判断HashMap中是否存在某个键，而应该用containsKey()方法来判断。 <br><br>4.其底层的实现机制不同，hashmap的访问速度要快于hashtable，因为它不需要进行同步检验，建议在非多线程环境中使用hashmap代替hashtable .
<img src ="http://www.blogjava.net/microlab4321/aggbug/137298.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/microlab4321/" target="_blank">冬天出走的猪</a> 2007-08-16 15:58 <a href="http://www.blogjava.net/microlab4321/articles/137298.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java性能调优续 </title><link>http://www.blogjava.net/microlab4321/articles/137296.html</link><dc:creator>冬天出走的猪</dc:creator><author>冬天出走的猪</author><pubDate>Thu, 16 Aug 2007 07:53:00 GMT</pubDate><guid>http://www.blogjava.net/microlab4321/articles/137296.html</guid><wfw:comment>http://www.blogjava.net/microlab4321/comments/137296.html</wfw:comment><comments>http://www.blogjava.net/microlab4321/articles/137296.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/microlab4321/comments/commentRss/137296.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/microlab4321/services/trackbacks/137296.html</trackback:ping><description><![CDATA[<h2><a name=_Toc123372421><span><font face=Arial size=4>3.2 </font></span></a><span><span><font size=4>字符串的调优</font></span></span></h2>
<p><font size=4><span><span><font face=Arial>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>下面列出一些常见的关于字符串优化的策略，简单的我就不多作解释了。</span></font></p>
<p><font size=4><span><font face=Arial>1) </font></span><span>使用规则表达式处理字符串匹配代替复杂的字符串查找和复制操作；</span></font></p>
<p><font size=4><span><font face=Arial>2) </font></span><span>使用不拷贝字符串中字符的高效方法，例如</span><span><font face=Arial>String.subString()</font></span><span>方法；</span></font></p>
<p><font size=4><span><font face=Arial>3) </font></span><span>尽可能不要使用需要拷贝字符串中字符的低效方法，例如</span><span><font face=Arial>String.toUpperCase()</font></span><span>和</span><span><font face=Arial>String.toLowercase()</font></span><span>；</span></font></p>
<p><font size=4><span><font face=Arial>4) </font></span><span>在编译期使用</span><span><font face=Arial>String</font></span><span>的&#8220;</span><span><font face=Arial>+</font></span><span>&#8221;操作符来执行连接操作，在运行期使用</span><span><font face=Arial>StringBuffer</font></span><span>执行连接操作；</span></font></p>
<p><font size=4><span>这里特别强调一下，因为我已经在网上看到好多文章都推荐使用</span><span><font face=Arial>StringBuffer</font></span><span>的</span><span><font face=Arial>append()</font></span><span>方法来做字符串的连接操作。其实在</span><span><font face=Arial>JVM</font></span><span>能够在编译期就能确定结果的情形，使用</span><span><font face=Arial>String</font></span><span>的&#8220;</span><span><font face=Arial>+</font></span><span>&#8221;操作符的性能要好很多。</span></font></p>
<h2><a name=_Toc123372422><span><font face=Arial size=4>3.3 </font></span></a><span><span><font size=4>异常，类型转换和变量</font></span></span></h2>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>1) </font></span><span>考虑在抛出异常的时候是否可以不即时生成堆栈信息而使用一个已有的异常实例；</span></font></p>
<p><font size=4><span><span><font face=Arial>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>创建异常的开销很大。当创建一个异常时，需要收集一个栈跟踪（</span><span><font face=Arial>Stack Trace</font></span><span>），这个栈跟踪用于描述异常是在何处创建的。构建这些栈跟踪时需要为运行时栈做一份快照，正是这一部分开销很大。运行时栈不是为有效的异常创建而设计的，而是设计用来让运行时尽可能快地运行。入栈，出栈，入栈，出栈。让这样的工作顺利完成，而没有任何不必要的延迟。但是，当需要创建一个</span><span><font face=Arial>Exception</font></span><span>时，</span><span><font face=Arial>JVM</font></span><span>不得不说：&#8220;先别动，我想就你现在的样子存一份快照，所以按时停止入栈和出栈操作，笑着等我拍完快照吧。&#8221;栈跟踪不只包含运行时栈中的一两个元素，而是包含这个栈中的每一个元素，从栈顶到栈底，还有行号和一切应有的东西。</span></font></p>
<p><font size=4><span><span><font face=Arial>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>因此，创建异常这一部分开销很大。从技术上讲，栈跟踪快照是在本地方法</span><span><font face=Arial>Throwable.fillInStackTrace()</font></span><span>中发生的，这个方法不是从</span><span><font face=Arial>Throwable contructor</font></span><span>那里调用的。但是这并并没有什么影响——如果你创建了一个</span><span><font face=Arial>Exception</font></span><span>，就得付出代价。好在捕获异常开销不大，因此可以用</span><span><font face=Arial>try-catch</font></span><span>将核心内容包起来。你也可以在方法定义中定义</span><span><font face=Arial>throws</font></span><span>子句，这样对性能不会造成什么损失。从技术上讲，你甚至可以随意地抛出异常，而不用花费很大的代价。招致性能损失的并不是</span><span><font face=Arial>throw</font></span><span>操作——尽管在没有预先创建异常的情况下就抛出异常是有点不寻常。真正要花代价的是创建异常。</span></font></p>
<p><font size=4><span><span><font face=Arial>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>幸运的是，好的编程习惯已教会我们，不应该不管三七二十一就抛出异常。异常是为异常的情况而设计的，使用时也应该牢记这一原则。但是，万一你不想遵从好的编程习惯，</span><span><font face=Arial>Java</font></span><span>语言就会让你知道，那样就可以让你的程序运行的更快，从而鼓励你去那样做。</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>2) </font></span><span>用</span><span><font face=Arial>instanceof</font></span><span>替代在</span><span><font face=Arial>try-catch</font></span><span>中做投机的强制类型转换方法；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>3) </font></span><span>尽可能少的使用强制类型转换方法，尤其是使用类型特定的集合类时；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>4) </font></span><span>使用</span><span><font face=Arial>int</font></span><span>优先于其他所有的数据类型；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>5) </font></span><span>尽可能使用基本数据类型做临时变量；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>6) </font></span><span>考虑直接获取实例变量而不通过</span><span><font face=Arial>get</font></span><span>，</span><span><font face=Arial>set</font></span><span>方法获取（注意：这不符合面向对象的封装原则，不推荐使用）。</span></font></p>
<h2><a name=_Toc123372423><span><font face=Arial size=4>3.4 </font></span></a><span><span><font size=4>循环，选择和递归</font></span></span></h2>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>1) </font></span><span>在循环中消除不必要的代码，做尽可能少的事情；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>2) Switch</font></span><span>语句中使用连续的</span><span><font face=Arial>case</font></span><span>值；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>3) </font></span><span>确定是否真的需要用到递归，最好转为用循环来实现。</span></font></p>
<h2><a name=_Toc123372424><span><font face=Arial size=4>3.5 </font></span></a><span><span><font size=4>输入输出操作</font></span></span></h2>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>1) </font></span><span>在程序中尽量不要使用</span><span><font face=Arial>System.out</font></span><span>这样的语句，而使用</span><span><font face=Arial>log4j</font></span><span>这样的日志工具替换，以在程序正式上线的时候可以关闭所有不必要的日志操作提高性能；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>2) </font></span><span>当程序中有大量的</span><span><font face=Arial>I/O</font></span><span>操作时，考虑将日志写入不同的文件做到并行化操作以提高性能，并可以用一个后台线程执行</span><span><font face=Arial>I/O</font></span><span>操作而不打断正常程序的执行；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>3) </font></span><span>正确的使用序列化机制，没有必要序列化的成员变量需要标识为</span><span><font face=Arial>transient</font></span><span>；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>4) </font></span><span>使用</span><span><font face=Arial>NIO</font></span><span>技术。</span></font></p>
<h2><a name=_Toc123372425><span><font face=Arial size=4>3.6 JDBC</font></span></a><span><font face=Arial size=4> </font></span></h2>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>1) </font></span><span>使用正确的</span><span><font face=Arial>JDBC</font></span><span>驱动，尽可能地选择最新的</span><span><font face=Arial>JDBC</font></span><span>驱动；</span></font></p>
<p><font size=4><span><span><font face=Arial>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>最新的</span><span><font face=Arial>JDBC</font></span><span>驱动不仅优化了性能，而且提供了更多的性能更好的接口供开发人员使用。</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>2) </font></span><span>使用应用服务器自带的连接池，而不要使用自己的连接池或干脆不用连接池；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>3) </font></span><span>在使用完数据库资源后，需依次关闭</span><span><font face=Arial>ResultSet</font></span><span>，</span><span><font face=Arial>Statement</font></span><span>和</span><span><font face=Arial>Connection</font></span><span>；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>4) </font></span><span>手动控制事务，使用</span><span><font face=Arial>connection.setAutoCommit(false)</font></span><span>关闭自动提交，使用</span><span><font face=Arial>executeBatch()</font></span><span>进行批量更新；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>5) </font></span><span>业务复杂或者大数据量操作时使用存储过程；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>6) ResultSet.next()</font></span><span>极其消耗性能，建议使用</span><span><font face=Arial>RowSet</font></span><span>替代</span><span><font face=Arial>ResultSet</font></span><span>；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>7) </font></span><span>把所有的字符数据都保存为</span><span><font face=Arial>Unicode</font></span><span>，</span><span><font face=Arial>Java</font></span><span>以</span><span><font face=Arial>UniCode</font></span><span>形式处理所有数据，数据库驱动程序不必再执行转换过程；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>8) </font></span><span>尽可能的优化</span><span><font face=Arial>SQL</font></span><span>语句；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>9) </font></span><span>少用</span><span><font face=Arial>join</font></span><span>，多用</span><span><font face=Arial>index</font></span><span>；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>10) </font></span><span>使用</span><span><font face=Arial>EXPLAIN</font></span><span>工具监控</span><span><font face=Arial>SQL</font></span><span>语句的执行，以确定瓶颈所在；</span></font></p>
<p><font size=4><span><span><font face=Arial>11)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>不要使用</span><span><font face=Arial> SELECT * ..., </font></span><span>使用</span><span><font face=Arial> SELECT Field1, Field1 ...</font></span><span>；</span></font></p>
<p><font size=4><span><span><font face=Arial>12)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>通过</span><span><font face=Arial>index</font></span><span>获取字段，而不要使用名字去获取，例如</span><span><font face=Arial>resultSet.getString(1) </font></span><span>而不是</span><span><font face=Arial> resultSet.getString("field1")</font></span><span>；</span></font></p>
<p><font size=4><span><span><font face=Arial>13)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>缓存数据，避免重复查询；</span></font></p>
<p><font size=4><span><span><font face=Arial>14)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>考虑使用内存数据库；</span></font></p>
<p><font size=4><span><span><font face=Arial>15)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>调整</span><span><font face=Arial>fetch size</font></span><span>进行批量查询；</span></font></p>
<p><font size=4><span><span><font face=Arial>16)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>尽可能的使</span><span><font face=Arial>Java</font></span><span>数据类型和数据库类型相匹配，转换数据在匹配不好的数据类型间效率太差；</span></font></p>
<p><font size=4><span><span><font face=Arial>17)</font>&nbsp;</span></span><span>避免使用低效的</span><span><font face=Arial>metadata</font></span><span>调用，尤其是</span><span><font face=Arial>getBestRowIdentifier( ), getColumns( ), getCrossReference( ), getExportedKeys( ), getImportedKeys( ), getPrimaryKeys( ), getTables( ), and getVersionColumns( )</font></span><span>；</span></font></p>
<p><font size=4><span><span><font face=Arial>18)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>使用</span><span><font face=Arial>metadata</font></span><span>查询减少数据库网络通信量；</span></font></p>
<p><font size=4><span><span><font face=Arial>19)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>使用最低的事务隔离级别；</span></font></p>
<p><font size=4><span><span><font face=Arial>20)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>使用乐观锁机制；</span></font></p>
<p><font size=4><span><span><font face=Arial>21)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>把应用服务器和数据库分散在不同的机器中，性能可能会更好。</span></font></p>
<h2><a name=_Toc123372426><span><font face=Arial size=4>3.7 Servlet</font></span></a><span><font size=4><span>和</span><span><font face=Arial>JSP</font></span></font></span></h2>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>1) Session</font></span><span>的使用；</span></font></p>
<p><font size=4><span><span><font face=Arial>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>应用服务器保存很多会话时，容易造成内存不足，所以尽量减少</span><span><font face=Arial>Session</font></span><span>的使用，放置到</span><span><font face=Arial>Session</font></span><span>中的对象不应该是大对象，最好是简单的小对象，实现串行化接口。当会话不再需要时，应当及时调用</span><span><font face=Arial>invalidate()</font></span><span>方法清除会话。而当某个变量不需要时，及时调用</span><span><font face=Arial>removeAttribute()</font></span><span>方法清除变量。当</span><span><font face=Arial>session</font></span><span>终止时需要清除不必要的资源，实现</span><span><font face=Arial>HttpSessionBindingListener</font></span><span>接口的</span><span><font face=Arial>valueUnbound()</font></span><span>方法。</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>2) </font></span><span>使用</span><span><font face=Arial>include directive</font></span><span>，而不使用</span><span><font face=Arial>include action</font></span><span>；</span></font></p>
<p><font size=4><span><span><font face=Arial>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>目前在</span><span><font face=Arial>JSP</font></span><span>页面中引入外部资源的方法主要有两种：</span><span><font face=Arial>include directive</font></span><span>和</span><span><font face=Arial>include action</font></span><span>。</span><span><font face=Arial>Include directive</font></span><span>：例如</span><span><font face=Arial>&lt;%@ include file=&#8221;copyright.html&#8221; %&gt;</font></span><span>，该指令在编译时引入指定的资源。在编译之前，带有</span><span><font face=Arial>include</font></span><span>指令的页面和指定的资源被合并成一个文件。被引用的资源在编译时就确定，比运行时才确定资源更高效。</span><span><font face=Arial>Include action</font></span><span>：例如</span><span><font face=Arial>&lt; jsp:include page=&#8221;copyright.jsp&#8221; /&gt;</font></span><span>，该动作引入指定页面执行后生成的结果。由于它在运行时完成，因此对输出结果的控制更加灵活。但是，只有当引用的内容被频繁改变时，或者在对主页面的请求没有出现之前，被引用的页面无法确定时，使用</span><span><font face=Arial>include action</font></span><span>才合算。</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>3) </font></span><span>对于那些无需跟踪会话状态的</span><span><font face=Arial>jsp</font></span><span>，关闭自动创建的会话可以节省一些资源。使用如下</span><span><font face=Arial>page</font></span><span>指令：</span><span><font face=Arial> &lt; %@ page session=&#8221;false&#8221; %&gt;</font></span><span>；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>4) </font></span><span>尽量不要把</span><span><font face=Arial>jsp</font></span><span>页面定义为单线程，应设置为</span><span><font face=Arial>&lt; %@page isThreadSafe=&#8221;true&#8221; %&gt;</font></span><span>；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>5) </font></span><span>在</span><span><font face=Arial>jsp</font></span><span>页面最好使用输出缓存功能，如：</span><span><font face=Arial>&lt; %@page buffer=&#8221;32kb&#8221; %&gt;</font></span><span>；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>6) </font></span><span>在</span><span><font face=Arial>servlet</font></span><span>之间跳转时，</span><span><font face=Arial>forward</font></span><span>比</span><span><font face=Arial>sendRedirect</font></span><span>更有效；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>7) </font></span><span>设置</span><span><font face=Arial>HttpServletResponse</font></span><span>缓冲区，如：</span><span><font face=Arial>response.setBufferSize(20000)</font></span><span>；</span></font></p>
<p><font size=4><span><font face=Arial><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>8) </font></span><span>建议在</span><span><font face=Arial>servlet</font></span><span>里使用</span><span><font face=Arial>ServletOutputStream</font></span><span>输出图片等对象；</span></font></p>
<p><font size=4><span><font face=Arial>9) </font></span><span>不要使用</span><span><font face=Arial>SingleThreadModel</font></span><span>，使</span><span><font face=Arial>Servlet</font></span><span>是线程安全的，但是尽可能的减少消耗在同步代码上的时间，使用足够多的</span><span><font face=Arial>servlet</font></span><span>去响应用户的请求；</span></font></p>
<p><font size=4><span><font face=Arial>10) </font></span><span>尽可能的使</span><span><font face=Arial>useBean</font></span><span>的范围在</span><span><font face=Arial>page</font></span><span>范围内；</span></font></p>
<p><font size=4><span><span><font face=Arial>11)</font>&nbsp;</span></span><span><font face=Arial>&nbsp;Servlet</font></span><span>的</span><span><font face=Arial>inti()</font></span><span>和</span><span><font face=Arial>destroy()</font></span><span>或</span><span><font face=Arial>jspInit()</font></span><span>和</span><span><font face=Arial>jspDestroy()</font></span><span>方法用于创建和删除昂贵的资源，例如缓存对象和数据库连接；</span></font></p>
<p><font size=4><span><span><font face=Arial>12)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>避免使用反向</span><span><font face=Arial>DNS</font></span><span>查找；</span></font></p>
<p><font size=4><span><span><font face=Arial>13)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>预编译</span><span><font face=Arial>JSP</font></span><span>页面；</span></font></p>
<p><font size=4><span><span><font face=Arial>14)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>尽可能的在客户段校验数据；</span></font></p>
<p><font size=4><span><span><font face=Arial>15)</font>&nbsp;</span></span><span><span><font face=Arial>&nbsp;</font></span></span><span>禁止自动装载特色防止周期性的装载</span><span><font face=Arial>servlet</font></span><span>和</span><span><font face=Arial>jsp</font></span><span>。</span></font></p>
<h2><a name=_Toc123372427><span><font face=Arial size=4>3.8 EJB</font></span></a></h2>
<p><font size=4><span><span><font face=Arial>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>由于</span><span><font face=Arial>EJB2.0</font></span><span>已经很少项目在用了，</span><span><font face=Arial>EJB3.0</font></span><span>再成熟一点，我再补充这一部分吧</span></font></p>
<img src ="http://www.blogjava.net/microlab4321/aggbug/137296.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/microlab4321/" target="_blank">冬天出走的猪</a> 2007-08-16 15:53 <a href="http://www.blogjava.net/microlab4321/articles/137296.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java垃圾回收机制 </title><link>http://www.blogjava.net/microlab4321/articles/137294.html</link><dc:creator>冬天出走的猪</dc:creator><author>冬天出走的猪</author><pubDate>Thu, 16 Aug 2007 07:51:00 GMT</pubDate><guid>http://www.blogjava.net/microlab4321/articles/137294.html</guid><wfw:comment>http://www.blogjava.net/microlab4321/comments/137294.html</wfw:comment><comments>http://www.blogjava.net/microlab4321/articles/137294.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/microlab4321/comments/commentRss/137294.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/microlab4321/services/trackbacks/137294.html</trackback:ping><description><![CDATA[<p><strong><span>引言</span></strong><span> </span></p>
<p><span>Java</span><span>的堆是一个运行时数据区<span>,</span>类的实例<span>(</span>对象<span>)</span>从中分配空间。<span>Java</span>虚拟机<span>(JVM)</span>的堆中储存着正在运行的应用程序所建立的所有对象，这些对象通过<span>new</span>、<span>newarray</span>、<span>anewarray</span>和<span>multianewarray</span>等指令建立，但是它们不需要程序代码来显式地释放。一般来说，堆的是由垃圾回收 来负责的，尽管<span>JVM</span>规范并不要求特殊的垃圾回收技术，甚至根本就不需要垃圾回收，但是由于内存的有限性，<span>JVM</span>在实现的时候都有一个由垃圾回收所管理的堆。垃圾回收是一种动态存储管理技术，它自动地释放不再被程序引用的对象，按照特定的垃圾收集算法来实现资源自动回收的功能。</span></p>
<p><strong><span>垃圾收集的意义</span></strong></p>
<p><span>在<span>C++</span>中，对象所占的内存在程序结束运行之前一直被占用，在明确释放之前不能分配给其它对象；而在<span>Java</span>中，当没有对象引用指向原先分配给某个对象的内存时，该内存便成为垃圾。<span>JVM</span>的一个系统级线程会自动释放该内存块。垃圾收集意味着程序不再需要的对象是<span>"</span>无用信息<span>"</span>，这些信息将被丢弃。当一个对象不再被引用的时候，内存回收它占领的空间，以便空间被后来的新对象使用。事实上，除了释放没用的对象，垃圾收集也可以清除内存记录碎片。由于创建对象和垃圾收集器释放丢弃对象所占的内存空间，内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆的一端，<span>JVM</span>将整理出的内存分配给新的对象。</span></p>
<p><span>垃圾收集能自动释放内存空间，减轻编程的负担。这使<span>Java </span>虚拟机具有一些优点。首先，它能使编程效率提高。在没有垃圾收集机制的时候，可能要花许多时间来解决一个难懂的存储器问题。在用<span>Java</span>语言编程的时候，靠垃圾收集机制可大大缩短时间。其次是它保护程序的完整性<span>, </span>垃圾收集是<span>Java</span>语言安全性策略的一个重要部份。</span></p>
<p><span>垃圾收集的一个潜在的缺点是它的开销影响程序性能。<span>Java</span>虚拟机必须追踪运行程序中有用的对象<span>, </span>而且最终释放没用的对象。这一个过程需要花费处理器的时间。其次垃圾收集算法的不完备性，早先采用的某些垃圾收集算法就不能保证<span>100%</span>收集到所有的废弃内存。当然随着垃圾收集算法的不断改进以及软硬件运行效率的不断提升，这些问题都可以迎刃而解。</span></p>
<p><strong><span>垃圾收集的算法分析</span></strong></p>
<p><span>Java</span><span>语言规范没有明确地说明<span>JVM</span>使用哪种垃圾回收算法，但是任何一种垃圾收集算法一般要做<span>2</span>件基本的事情：（<span>1</span>）发现无用信息对象；（<span>2</span>）回收被无用对象占用的内存空间，使该空间可被程序再次使用。</span></p>
<p><span>大多数垃圾回收算法使用了根集<span>(root set)</span>这个概念；所谓根集就量正在执行的<span>Java</span>程序可以访问的引用变量的集合<span>(</span>包括局部变量、参数、类变量<span>)</span>，程序可以使用引用变量访问对象的属性和调用对象的方法。垃圾收集首选需要确定从根开始哪些是可达的和哪些是不可达的，从根集可达的对象都是活动对象，它们不能作为垃圾被回收，这也包括从根集间接可达的对象。而根集通过任意路径不可达的对象符合垃圾收集的条件，应该被回收。下面介绍几个常用的算法。</span></p>
<p><span><span>1、&nbsp;</span></span><span>引用计数法</span><span>(Reference Counting Collector)</span></p>
<p><span>引用计数法是唯一没有使用根集的垃圾回收的法，该算法使用引用计数器来区分存活对象和不再使用的对象。一般来说，堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时，引用计数器置为<span>1</span>。当对象被赋给任意变量时，引用计数器每次加<span>1</span>当对象出了作用域后<span>(</span>该对象丢弃不再使用<span>)</span>，引用计数器减<span>1</span>，一旦引用计数器为<span>0</span>，对象就满足了垃圾收集的条件。</span></p>
<p><span>基于引用计数器的垃圾收集器运行较快，不会长时间中断程序执行，适宜地必须 实时运行的程序。但引用计数器增加了程序执行的开销，因为每次对象赋给新的变量，计数器加<span>1</span>，而每次现有对象出了作用域生，计数器减<span>1</span>。</span></p>
<p><span>2</span><span>、<span>tracing</span><span>算法</span><span>(Tracing Collector)</span></span></p>
<p><span>tracing</span><span>算法是为了解决引用计数法的问题而提出，它使用了根集的概念。基于<span>tracing</span>算法的垃圾收集器从根集开始扫描，识别出哪些对象可达，哪些对象不可达，并用某种方式标记可达对象，例如对每个可达对象设置一个或多个位。在扫描识别过程中，基于<span>tracing</span>算法的垃圾收集也称为标记和清除<span>(mark-and-sweep)</span>垃圾收集器<span>.</span></span></p>
<p><span>3</span><span>、<span>compacting</span>算法<span>(Compacting Collector)</span></span></p>
<p><span>为了解决堆碎片问题，基于<span>tracing</span>的垃圾回收吸收了<span>Compacting</span>算法的思想，在清除的过程中，算法将所有的对象移到堆的一端，堆的另一端就变成了一个相邻的空闲内存区，收集器会对它移动的所有对象的所有引用进行更新，使得这些引用在新的位置能识别原来 的对象。在基于<span>Compacting</span>算法的收集器的实现中，一般增加句柄和句柄表。　　</span></p>
<p><span>4</span><span>、<span>copying</span><span>算法</span><span>(Coping Collector)</span></span></p>
<p><span>该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成 一个对象 面和多个空闲面， 程序从对象面为对象分配空间，当对象满了，基于<span>coping</span>算法的垃圾 收集就从根集中扫描活动对象，并将每个 活动对象复制到空闲面<span>(</span>使得活动对象所占的内存之间没有空闲洞<span>)</span>，这样空闲面变成了对象面，原来的对象面变成了空闲面，程序会在新的对象面中分配内存。</span></p>
<p><span>一种典型的基于<span>coping</span>算法的垃圾回收是<span>stop-and-copy</span>算法，它将堆分成对象面和空闲区域面，在对象面与空闲区域面的切换过程中，程序暂停执行。</span></p>
<p><span>5</span><span>、<span>generation</span>算法<span>(Generational Collector)<br></span>　　<span>stop-and-copy</span>垃圾收集器的一个缺陷是收集器必须复制所有的活动对象，这增加了程序等待时间，这是<span>coping</span>算法低效的原因。在程序设计中有这样的规律：多数对象存在的时间比较短，少数的存在时间比较长。因此，<span>generation</span>算法将堆分成两个或多个，每个子堆作为对象的一代<span>(generation)</span>。由于多数对象存在的时间比较短，随着程序丢弃不使用的对象，垃圾收集器将从最年轻的子堆中收集这些对象。在分代式的垃圾收集器运行后，上次运行存活下来的对象移到下一最高代的子堆中，由于老一代的子堆不会经常被回收，因而节省了时间。</span></p>
<p><span>6</span><span>、<span>adaptive</span>算法<span>(Adaptive Collector)</span></span></p>
<p><span>在特定的情况下，一些垃圾收集算法会优于其它算法。基于<span>Adaptive</span>算法的垃圾收集器就是监控当前堆的使用情况，并将选择适当算法的垃圾收集器。</span></p>
<p><strong><span>透视<span>Java</span>垃圾回收</span></strong></p>
<p><span>1</span><span>、命令行参数透视垃圾收集器的运行</span></p>
<p><span>2</span><span>、使用<span>System.gc()</span>可以不管<span>JVM</span>使用的是哪一种垃圾回收的算法，都可以请求<span>Java</span>的垃圾回收。在命令行中有一个参数<span>-verbosegc</span>可以查看<span>Java</span>使用的堆内存的情况，它的格式如下：<span><br><br><span>java -verbosegc classfile</span><br><br></span>　　可以看个例子：</span></p>
<p><span>class TestGC <br>{<br></span><span>　<span>public static void main(String[] args) <br></span>　<span>{<br></span>　　<span>new TestGC();<br></span>　　<span>System.gc();<br></span>　　<span>System.runFinalization();<br></span>　<span>}<br>}</span></span></p>
<p><span><br></span><span>　　在这个例子中，一个新的对象被创建，由于它没有使用，所以该对象迅速地变为可达，程序编译后，执行命令：<span> java -verbosegc TestGC </span>后结果为：<span><br><br>[Full GC 168K-&gt;97K(1984K), 0.0253873 secs]<br><br></span>　　机器的环境为，<span>Windows 2000 + JDK<st1:chsdate Year="1899" Month="12" Day="30" IsLunarDate="False" IsROCDate="False" w:st="on">1.3.1</st1:chsdate>,</span>箭头前后的数据<span>168K</span>和<span>97K</span>分别表示垃圾收集<span>GC</span>前后所有存活对象使用的内存容量，说明有<span>168K-97K=71K</span>的对象容量被回收，括号内的数据<span>1984K</span>为堆内存的总容量，收集所需要的时间是<span>0.0253873</span>秒（这个时间在每次执行的时候会有所不同）。<span><br><br></span>　　<span>2</span>、<span>finalize</span>方法透视垃圾收集器的运行<span><br><br></span>　　在<span>JVM</span>垃圾收集器收集一个对象之前 ，一般要求程序调用适当的方法释放资源，但在没有明确释放资源的情况下，<span>Java</span>提供了缺省机制来终止化该对象心释放资源，这个方法就是<span>finalize</span>（）。它的原型为：<span><br><br>protected void finalize() throws Throwable<br><br></span>　　在<span>finalize()</span>方法返回之后，对象消失，垃圾收集开始执行。原型中的<span>throws Throwable</span>表示它可以抛出任何类型的异常。<span><br><br></span>　　之所以要使用<span>finalize()</span>，是由于有时需要采取与<span>Java</span>的普通方法不同的一种方法，通过分配内存来做一些具有<span>C</span>风格的事情。这主要可以通过<span>"</span>固有方法<span>"</span>来进行，它是从<span>Java</span>里调用非<span>Java</span>方法的一种方式。<span>C</span>和<span>C++</span>是目前唯一获得固有方法支持的语言。但由于它们能调用通过其他语言编写的子程序，所以能够有效地调用任何东西。在非<span>Java</span>代码内部，也许能调用<span>C</span>的<span>malloc()</span>系列函数，用它分配存储空间。而且除非调用了<span>free()</span>，否则存储空间不会得到释放，从而造成内存<span>"</span>漏洞<span>"</span>的出现。当然，<span>free()</span>是一个<span>C</span>和<span>C++</span>函数，所以我们需要在<span>finalize()</span>内部的一个固有方法中调用它。也就是说我们不能过多地使用<span>finalize()</span>，它并不是进行普通清除工作的理想场所。<span><br><br></span>　　在普通的清除工作中，为清除一个对象，那个对象的用户必须在希望进行清除的地点调用一个清除方法。这与<span>C++"</span>破坏器<span>"</span>的概念稍有抵触。在<span>C++</span>中，所有对象都会破坏（清除）。或者换句话说，所有对象都<span>"</span>应该<span>"</span>破坏。若将<span>C++</span>对象创建成一个本地对象，比如在堆栈中创建（在<span>Java</span>中是不可能的），那么清除或破坏工作就会在<span>"</span>结束花括号<span>"</span>所代表的、创建这个对象的作用域的末尾进行。若对象是用<span>new</span>创建的（类似于<span>Java</span>），那么当程序员调用<span>C++</span>的<span>delete</span>命令时（<span>Java</span>没有这个命令），就会调用相应的破坏器。若程序员忘记了，那么永远不会调用破坏器，我们最终得到的将是一个内存<span>"</span>漏洞<span>"</span>，另外还包括对象的其他部分永远不会得到清除。<span><br><br></span>　　相反，<span>Java</span>不允许我们创建本地（局部）对象<span>--</span>无论如何都要使用<span>new</span>。但在<span>Java</span>中，没有<span>"delete"</span>命令来释放对象，因为垃圾收集器会帮助我们自动释放存储空间。所以如果站在比较简化的立场，我们可以说正是由于存在垃圾收集机制，所以<span>Java</span>没有破坏器。然而，随着以后学习的深入，就会知道垃圾收集器的存在并不能完全消除对破坏器的需要，或者说不能消除对破坏器代表的那种机制的需要（而且绝对不能直接调用<span>finalize()</span>，所以应尽量避免用它）。若希望执行除释放存储空间之外的其他某种形式的清除工作，仍然必须调用<span>Java</span>中的一个方法。它等价于<span>C++</span>的破坏器，只是没后者方便。<span><br><br></span>　　下面这个例子向大家展示了垃圾收集所经历的过程，并对前面的陈述进行了总结。</span></p>
<p><span>class Chair {<br></span><span>　<span>static boolean gcrun = false;<br></span>　<span>static boolean f = false;<br></span>　<span>static int created = 0;<br></span>　<span>static int finalized = 0;<br></span>　<span>int i;<br></span>　<span>Chair() {<br></span>　　<span>i = ++created;<br></span>　　<span>if(created == 47) <br></span>　　　<span>System.out.println("Created 47");<br></span>　<span>}<br></span>　<span>protected void finalize() {<br></span>　　<span>if(!gcrun) {<br></span>　　　<span>gcrun = true;<br></span>　　　<span>System.out.println("Beginning to finalize after " + created + " Chairs have been created");<br></span>　　<span>}<br></span>　　<span>if(i == 47) {<br></span>　　　<span>System.out.println("Finalizing Chair #47, " +"Setting flag to stop Chair creation");<br></span>　　　<span>f = true;<br></span>　　<span>}<br></span>　　<span>finalized++;<br></span>　　<span>if(finalized &gt;= created)<br></span>　　　<span>System.out.println("All " + finalized + " finalized");<br></span>　<span>}<br>}<br><br>public class Garbage {<br></span>　<span>public static void main(String[] args) {<br></span>　　<span>if(args.length == 0) {<br></span>　　　<span>System.err.println("Usage: \n" + "java Garbage before\n or:\n" + "java Garbage after");<br></span>　　　<span>return;<br></span>　　<span>}<br></span>　　<span>while(!Chair.f) {<br></span>　　　<span>new Chair();<br></span>　　　<span>new String("To take up space");<br></span>　　<span>}<br></span>　　<span>System.out.println("After all Chairs have been created:\n" + "total created = " + Chair.created +<br>", total finalized = " + Chair.finalized);<br></span>　　<span>if(args[0].equals("before")) {<br></span>　　　　<span>System.out.println("gc():");<br></span>　　　　<span>System.gc();<br></span>　　　　<span>System.out.println("runFinalization():");<br></span>　　　　<span>System.runFinalization();<br></span>　　<span>}<br></span>　　<span>System.out.println("bye!");<br></span>　　<span>if(args[0].equals("after"))<br></span>　　　<span>System.runFinalizersOnExit(true);<br></span>　<span>}<br>}</span></span></p>
<p><span><br></span><span>　　上面这个程序创建了许多<span>Chair</span>对象，而且在垃圾收集器开始运行后的某些时候，程序会停止创建<span>Chair</span>。由于垃圾收集器可能在任何时间运行，所以我们不能准确知道它在何时启动。因此，程序用一个名为<span>gcrun</span>的标记来指出垃圾收集器是否已经开始运行。利用第二个标记<span>f</span>，<span>Chair</span>可告诉<span>main()</span>它应停止对象的生成。这两个标记都是在<span>finalize()</span>内部设置的，它调用于垃圾收集期间。另两个<span>static</span>变量<span>--created</span>以及<span>finalized--</span>分别用于跟踪已创建的对象数量以及垃圾收集器已进行完收尾工作的对象数量。最后，每个<span>Chair</span>都有它自己的（非<span>static</span>）<span>int i</span>，所以能跟踪了解它具体的编号是多少。编号为<span>47</span>的<span>Chair</span>进行完收尾工作后，标记会设为<span>true</span>，最终结束<span>Chair</span>对象的创建过程。（关于这个例子的更具体的分析和说明请参看《<span>Java</span>编程思想》的第四章）<span><br><br></span>　　<strong>关于垃圾收集的几点补充</strong><span><br><br></span>　　经过上述的说明，可以发现垃圾回收有以下的几个特点：<span><br><br></span>　　（<span>1</span>）垃圾收集发生的不可预知性：由于实现了不同的垃圾收集算法和采用了不同的收集机制，所以它有可能是定时发生，有可能是当出现系统空闲<span>CPU</span>资源时发生，也有可能是和原始的垃圾收集一样，等到内存消耗出现极限时发生，这与垃圾收集器的选择和具体的设置都有关系。<span><br><br></span>　　（<span>2</span>）垃圾收集的精确性：主要包括<span>2 </span>个方面：（<span>a</span>）垃圾收集器能够精确标记活着的对象；（<span>b</span>）垃圾收集器能够精确地定位对象之间的引用关系。前者是完全地回收所有废弃对象的前提，否则就可能造成内存泄漏。而后者则是实现归并和复制等算法的必要条件。所有不可达对象都能够可靠地得到回收，所有对象都能够重新分配，允许对象的复制和对象内存的缩并，这样就有效地防止内存的支离破碎。（<span>3</span>）现在有许多种不同的垃圾收集器，每种有其算法且其表现各异，既有当垃圾收集开始时就停止应用程序的运行，又有当垃圾收集开始时也允许应用程序的线程运行，还有在同一时间垃圾收集多线程运行。<span><br><br></span>　　（<span>4</span>）垃圾收集的实现和具体的<span>JVM </span>以及<span>JVM</span>的内存模型有非常紧密的关系。不同的<span>JVM </span>可能采用不同的垃圾收集，而<span>JVM </span>的内存模型决定着该<span>JVM</span>可以采用哪些类型垃圾收集。现在，<span>HotSpot </span>系列<span>JVM</span>中的内存系统都采用先进的面向对象的框架设计，这使得该系列<span>JVM</span>都可以采用最先进的垃圾收集。<span><br><br></span>　　（<span>5</span>）随着技术的发展，现代垃圾收集技术提供许多可选的垃圾收集器，而且在配置每种收集器的时候又可以设置不同的参数，这就使得根据不同的应用环境获得最优的应用性能成为可能。<span><br><br></span>　　针对以上特点，我们在使用的时候要注意：<span><br><br></span>　　（<span>1</span>）不要试图去假定垃圾收集发生的时间，这一切都是未知的。比如，方法中的一个临时对象在方法调用完毕后就变成了无用对象，这个时候它的内存就可以被释放。<span><br><br></span>　　（<span>2</span>）<span>Java</span>中提供了一些和垃圾收集打交道的类，而且提供了一种强行执行垃圾收集的方法<span>--</span>调用<span>System.gc()</span>，但这同样是个不确定的方法。<span>Java </span>中并不保证每次调用该方法就一定能够启动垃圾收集，它只不过会向<span>JVM</span>发出这样一个申请，到底是否真正执行垃圾收集，一切都是个未知数。<span><br><br></span>　　（<span>3</span>）挑选适合自己的垃圾收集器。一般来说，如果系统没有特殊和苛刻的性能要求，可以采用<span>JVM</span>的缺省选项。否则可以考虑使用有针对性的垃圾收集器，比如增量收集器就比较适合实时性要求较高的系统之中。系统具有较高的配置，有比较多的闲置资源，可以考虑使用并行标记<span>/</span>清除收集器。<span><br><br></span>　　（<span>4</span>）关键的也是难把握的问题是内存泄漏。良好的编程习惯和严谨的编程态度永远是最重要的，不要让自己的一个小错误导致内存出现大漏洞。<span><br><br></span>　　（<span>5</span>）尽早释放无用对象的引用。大多数程序员在使用临时变量的时候，都是让引用变量在退出活动域<span>(scope)</span>后，自动设置为<span>null</span>，暗示垃圾收集器来收集该对象，还必须注意该引用的对象是否被监听，如果有，则要去掉监听器，然后再赋空值。<span><br><br></span>　　<strong>结束语</strong><span><br><br></span>　　一般来说，<span>Java</span>开发人员可以不重视<span>JVM</span>中堆内存的分配和垃圾处理收集，但是，充分理解<span>Java</span>的这一特性可以让我们更有效地利用资源。同时要注意<span>finalize()</span>方法是<span>Java</span>的缺省机制，有时为确保对象资源的明确释放，可以编写自己的<span>finalize</span>方法。</span></p>
<img src ="http://www.blogjava.net/microlab4321/aggbug/137294.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/microlab4321/" target="_blank">冬天出走的猪</a> 2007-08-16 15:51 <a href="http://www.blogjava.net/microlab4321/articles/137294.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JRE与JDK在启动应用服务器中的作用(摘录)</title><link>http://www.blogjava.net/microlab4321/articles/136293.html</link><dc:creator>冬天出走的猪</dc:creator><author>冬天出走的猪</author><pubDate>Mon, 13 Aug 2007 02:01:00 GMT</pubDate><guid>http://www.blogjava.net/microlab4321/articles/136293.html</guid><wfw:comment>http://www.blogjava.net/microlab4321/comments/136293.html</wfw:comment><comments>http://www.blogjava.net/microlab4321/articles/136293.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/microlab4321/comments/commentRss/136293.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/microlab4321/services/trackbacks/136293.html</trackback:ping><description><![CDATA[&nbsp;&nbsp; 开始接触Java的时候觉得Java虚拟机很麻烦，不明白JRE与JDK的区别是什么？后来搞清楚JRE是个运行环境，JDK是个开发环境。因此写Java程序的时候需要JDK，而运行Java程序的时候就需要JRE。而JDK里面已经包含了JRE，因此对JAVA_HOME设置为JDK的路径时也可以正常运行Java程序，但是JDK比较大包括了许多与运行无关的内容，因此运行普通的Java程序无须安装JDK。<br><br>&nbsp;&nbsp;&nbsp; 但是用了Eclipse又有了疑问，为什么这个开发环境JRE就可以正常运行呢？其实在Eclipse中内嵌了Java编译器，并且与JDK中的javac完全相容，因此无须使用JDK也可以直接编译Java程序。<br><br>&nbsp;&nbsp;&nbsp; 学习J2EE的时候又开始不明白，为什么Tomcat和Apusic用JRE就可以启动，Weblogic用JDK才能启动呢？原因是Tomcat和Apusic 4都已经包括了一个源代码编译器，而Weblogic没有包括这个编译器包。<br><br>&nbsp;&nbsp;&nbsp; 那么为什么需要编译器呢？因为在WEB应用中JSP文件是需要转换成Servlet，这个Servlet文件还需要编译成可以在JRE上执行的class文件，因此必须提供有编译能力的JDK，将JAVA_HOME设置为JDK的路径就可以了。<br><br>&nbsp;&nbsp;&nbsp; 那么新出现的Apusic 5.0呢？这个版本为了使大家可以灵活调整JVM的版本，因此不再提供自带的Java编译器，而是通过用户安装的JDK来完成JSP的编译工作，这个也就是为什么Apusic 5.0必须通过JDK启动的原因。
<img src ="http://www.blogjava.net/microlab4321/aggbug/136293.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/microlab4321/" target="_blank">冬天出走的猪</a> 2007-08-13 10:01 <a href="http://www.blogjava.net/microlab4321/articles/136293.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>