??xml version="1.0" encoding="utf-8" standalone="yes"?> 下面列出一些常见的关于字符串优化的{略Q简单的我就不多作解释了(jin)?/span> 1) 使用规则表达式处理字W串匚w代替复杂的字W串查找和复制操作; 2) 使用不拷贝字W串中字W的高效Ҏ(gu)Q例?/span>String.subString()Ҏ(gu)Q?/span> 3) 可能不要用需要拷贝字W串中字W的低效Ҏ(gu)Q例?/span>String.toUpperCase()?/span>String.toLowercase()Q?/span> 4) 在编译期使用String?#8220;+”操作W来执行q接操作Q在q行期?/span>StringBuffer执行q接操作Q?/span> q里特别一下,因ؓ(f)我已l在|上看到好多文章都推荐?/span>StringBuffer?/span>append()Ҏ(gu)来做字符串的q接操作。其实在JVM能够在编译期p定l果的情形,使用String?#8220;+”操作W的性能要好很多?/span> 1) 考虑在抛出异常的时候是否可以不x(chng)生成堆栈信息而用一个已有的异常实例Q?/span> 创徏异常的开销很大。当创徏一个异常时Q需要收集一个栈跟踪Q?/span>Stack TraceQ,q个栈跟t用于描q异常是在何处创建的。构些栈跟踪旉要ؓ(f)q行时栈做一份快照,正是q一部分开销很大。运行时栈不是ؓ(f)有效的异常创设计的Q而是设计用来让运行时可能快地运行。入栈,出栈Q入栈,出栈。让q样的工作顺利完成,而没有Q何不必要的gq。但是,当需要创Z?/span>ExceptionӞJVM不得不说Q?#8220;先别动,我想׃现在的样子存?sh)份快照,所以按时停止入栈和出栈操作Q笑着{我拍完快照吧?#8221;栈跟t不只包含运行时栈中的一两个元素Q而是包含q个栈中的每一个元素,从栈到栈底Q还有行号和一切应有的东西?/span> 因此Q创建异常这一部分开销很大。从技术上Ԍ栈跟t快照是在本地方?/span>Throwable.fillInStackTrace()中发生的Q这个方法不是从Throwable contructor那里调用的。但是这qƈ没有什么媄(jing)响——如果你创徏?jin)一?/span>ExceptionQ就得付Z仗好在捕获异常开销不大Q因此可以用try-catch核?j)内容包h。你也可以在Ҏ(gu)定义中定?/span>throws子句Q这样对性能不会(x)造成什么损失。从技术上Ԍ你甚臛_以随意地抛出异常Q而不用花费很大的代h(hun)。招致性能损失的ƈ不是throw操作——尽在没有预先创徏异常的情况下抛出异常是有点不寻常。真正要׃L(fng)是创建异常?/span> q运的是Q好的编E习(fn)惯已教会(x)我们Q不应该不管三七二十一抛出异常。异常是为异常的情况而设计的Q用时也应该牢记这一原则。但是,万一你不想遵从好的编E习(fn)惯,Java语言׃(x)让你知道Q那样就可以让你的程序运行的更快Q从而鼓׃去那样做?/span> 2) ?/span>instanceof替代?/span>try-catch中做投机的强制类型{换方法; 3) 可能少的用强制类型{换方法,其是用类型特定的集合cLQ?/span> 4) 使用int优先于其他所有的数据cdQ?/span> 5) 可能用基本数据类型做临时变量Q?/span> 6) 考虑直接获取实例变量而不通过getQ?/span>setҎ(gu)获取Q注意:(x)q不W合面向对象的封装原则,不推荐用)(j)?/span> 1) 在@环中消除不必要的代码Q做可能少的事情; 2) Switch语句中用连l的case| 3) 定是否真的需要用到递归Q最好{为用循环来实现?/span> 1) 在程序中量不要使用System.outq样的语句,而?/span>log4jq样的日志工h换,以在E序正式上线的时候可以关闭所有不必要的日志操作提高性能Q?/span> 2) 当程序中有大量的I/O操作Ӟ考虑日志写入不同的文g做到q行化操作以提高性能Qƈ可以用一个后台线E执?/span>I/O操作而不打断正常E序的执行; 3) 正确的用序列化机制Q没有必要序列化的成员变量需要标识ؓ(f)transientQ?/span> 4) 使用NIO技术?/span> 1) 使用正确?/span>JDBC驱动Q尽可能地选择最新的JDBC驱动Q?/span> 最新的JDBC驱动不仅优化?jin)性能Q而且提供?jin)更多的性能更好的接口供开发h员(sh)用?/span> 2) 使用应用服务器自带的q接池,而不要用自qq接池或q脆不用q接池; 3) 在用完数据库资源后Q需依次关闭ResultSetQ?/span>Statement?/span>ConnectionQ?/span> 4) 手动控制事务Q?/span>connection.setAutoCommit(false)关闭自动提交Q?/span>executeBatch()q行扚w更新Q?/span> 5) 业务复杂或者大数据量操作时使用存储q程Q?/span> 6) ResultSet.next()极其消耗性能Q徏议?/span>RowSet替代ResultSetQ?/span> 7) 把所有的字符数据都保存(sh)ؓ(f)UnicodeQ?/span>Java?/span>UniCode形式处理所有数据,数据库驱动程序不必再执行转换q程Q?/span> 8) 可能的优化SQL语句Q?/span> 9) 用joinQ多?/span>indexQ?/span> 10) 使用EXPLAIN工具监控SQL语句的执行,以确定瓶颈所在; 11) 不要使用 SELECT * ..., 使用 SELECT Field1, Field1 ...Q?/span> 12) 通过index获取字段Q而不要用名字去获取Q例?/span>resultSet.getString(1) 而不?/span> resultSet.getString("field1")Q?/span> 13) ~存数据Q避免重复查询; 14) 考虑使用内存数据库; 15) 调整fetch sizeq行扚w查询Q?/span> 16) 可能的?/span>Java数据cd和数据库cd相匹配,转换数据在匹配不好的数据cd间效率太差; 17) 避免使用低效?/span>metadata调用Q尤其是getBestRowIdentifier( ), getColumns( ), getCrossReference( ), getExportedKeys( ), getImportedKeys( ), getPrimaryKeys( ), getTables( ), and getVersionColumns( )Q?/span> 18) 使用metadata查询减少数据库网l通信量; 19) 使用最低的事务隔离U别Q?/span> 20) 使用乐观锁机Ӟ 21) 把应用服务器和数据库分散在不同的机器中,性能可能?x)更好?/span> 1) Session的用; 应用服务器保存很多会(x)话时Q容易造成内存?sh)Q所以尽量减?/span>Session的用,攄?/span>Session中的对象不应该是大对象,最好是单的对象,实现串行化接口。当?x)话不再需要时Q应当及(qing)时调?/span>invalidate()Ҏ(gu)清除?x)话。而当某个变量不需要时Q及(qing)时调?/span>removeAttribute()Ҏ(gu)清除变量。当sessionl止旉要清除不必要的资源,实现HttpSessionBindingListener接口?/span>valueUnbound()Ҏ(gu)?/span> 2) 使用include directiveQ而不使用include actionQ?/span> 目前?/span>JSP面中引入外部资源的Ҏ(gu)主要有两U:(x)include directive?/span>include action?/span>Include directiveQ例?/span><%@ include file=”copyright.html” %>Q该指o(h)在编译时引入指定的资源。在~译之前Q带?/span>include指o(h)的页面和指定的资源被合ƈ成一个文件。被引用的资源在~译时就定Q比q行时才定资源更高效?/span>Include actionQ例?/span>< jsp:include page=”copyright.jsp” />Q该动作引入指定面执行后生成的l果。由于它在运行时完成Q因此对输出l果的控制更加灵zR但是,只有当引用的内容被频J改变时Q或者在对主面的请求没有出C前,被引用的面无法定Ӟ使用include action才合?/span> 3) 对于那些无需跟踪?x)话状态的jspQ关闭自动创建的?x)话可以节省一些资源。用如?/span>page指o(h)Q?/span> < %@ page session=”false” %>Q?/span> 4) 量不要?/span>jsp面定义为单U程Q应讄?/span>< %@page isThreadSafe=”true” %>Q?/span> 5) ?/span>jsp面最好用输出缓存功能,如:(x)< %@page buffer=”32kb” %>Q?/span> 6) ?/span>servlet之间跌{Ӟforward?/span>sendRedirect更有效; 7) 讄HttpServletResponse~冲区,如:(x)response.setBufferSize(20000)Q?/span> 8) ?/span>servlet里?/span>ServletOutputStream输出囄{对象; 9) 不要使用SingleThreadModelQServlet是线E安全的Q但是尽可能的减消耗在同步代码上的旉Q用够多?/span>servletd应用L(fng)hQ?/span> 10) 可能的?/span>useBean的范围在page范围内; 11) Servlet?/span>inti()?/span>destroy()?/span>jspInit()?/span>jspDestroy()Ҏ(gu)用于创徏和删除昂늚资源Q例如缓存对象和数据库连接; 12) 避免使用反向DNS查找Q?/span> 13) 预编?/span>JSP面Q?/span> 14) 可能的在客h校验数据Q?/span> 15) 止自动装蝲特色防止周期性的装蝲servlet?/span>jsp?/span> ׃EJB2.0已经很少目在用?jin)?/span>EJB3.0再成熟一点,我再补充q一部分?/span>
lgQ简单的讄Ҏ(gu)如下Q?br>
jsp (gbk) ----> java(ISO-8859-1) -------> mysql(gbk)
转换
q样讄之后Q还有一U情况会(x)出现qQ当你在jsp端提交一个idP然后在java处理端通过id号得到数据库中的gbkQ汉字)(j)数据Q这是就?x)出Cؕ码,因ؓ(f)java处理的是ISO-8859-1Q你在java到mysql中有?jin)一个ISO-8859-1到gbk的{换,而这些数据本w就是ISO-8859-1,所以{换后出现问题(sh)(jin)?br>解决办法Q将在java中处理的gbk数据转换为ISO-8859-1卛_?br>
MQ在jspQjavaQmysql三者之间的~码方式必须l一Q不能错误的转换或者不转换?
]]>
2.Hashtable中的Ҏ(gu)是同步的Q而HashMap中的Ҏ(gu)在缺省情况下是非同步的。即是说Q在多线E应用程序中Q不用专门的操作安全地可以使用Hashtable?jin);而对于HashMapQ则需要额外的同步机制。但HashMap的同步问题可通过Collections的一个静(rn)态方法得到解冻I(x)
Map Collections.synchronizedMap(Map m)
q个Ҏ(gu)q回一个同步的MapQ这个Map装?jin)底层的HashMap的所有方法,使得底层的HashMap即是在多线E的环境中也是安全的?br>
3.在HashMap中,null可以作ؓ(f)键,q样的键只有一个;可以有一个或多个键所对应的gؓ(f)null。当get()Ҏ(gu)q回null值时Q即可以表示HashMap中没有该键,也可以表C键所对应的gؓ(f)null。因此,在HashMap中不能由get()Ҏ(gu)来判断HashMap中是否存在某个键Q而应该用containsKey()Ҏ(gu)来判断?
4.其底层的实现机制不同Qhashmap的访问速度要快于hashtableQ因为它不需要进行同步检验,在非多线E环境中使用hashmap代替hashtable .
]]>3.3 异常Q类型{换和变量
3.4 循环Q选择和递归
3.5 输入输出操作
3.6 JDBC
3.7 Servlet?/span>JSP
3.8 EJB
]]>
Java的堆是一个运行时数据?span>,cȝ实例(对象)从中分配I间?span>Java虚拟?span>(JVM)的堆中储存着正在q行的应用程序所建立的所有对象,q些对象通过new?span>newarray?span>anewarray?span>multianewarray{指令徏立,但是它们不需要程序代码来昑ּ地释放。一般来_(d)堆的是由垃圾回收 来负责的Q尽?span>JVM规范q不要求Ҏ(gu)的垃圑֛收技术,甚至Ҏ(gu)׃需要垃圑֛Ӟ但是׃内存的有限性,JVM在实现的时候都有一个由垃圾回收所理的堆。垃圑֛收是一U动态存储管理技术,它自动地释放不再被程序引用的对象Q按照特定的垃圾攉法来实现资源自动回收的功能?/span>
垃圾攉的意?/span>
?span>C++中,对象所占的内存在程序结束运行之前一直被占用Q在明确释放之前不能分配l其它对象;而在Java中,当没有对象引用指向原先分配给某个对象的内存时Q该内存?sh)成为垃圾?span>JVM的一个系lU程?x)自动释放该内存块。垃圾收集意味着E序不再需要的对象?span>"无用信息"Q这些信息将被丢弃。当一个对象不再被引用的时候,内存回收它占领的I间Q以便空间被后来的新对象使用。事实上Q除?jin)释放没用的对象Q垃圾收集也可以清除内存记录片。由于创建对象和垃圾攉器释放丢弃对象所占的内存I间Q内存(sh)(x)出现片。碎片是分配l对象的内存块之间的I闲内存?gu)z。碎片整理将所占用的堆内存Ud堆的一端,JVM整理出的内存分配给新的对象?/span>
垃圾攉能自动释攑ֆ存空_(d)减轻~程的负担。这?span>Java 虚拟机具有一些优炏V首先,它能使编E效率提高。在没有垃圾攉机制的时候,可能要花许多旉来解决一个难懂的存储器问题。在?span>Java语言~程的时候,靠垃圾收集机制可大大~短旉。其ơ是它保护程序的完整?span>, 垃圾攉?span>Java语言安全性策略的一个重要部份?/span>
垃圾攉的一个潜在的~点是它的开销影响E序性能?span>Java虚拟机必追t运行程序中有用的对?span>, 而且最l释放没用的对象。这一个过E需要花费处理器的时间。其ơ垃圾收集算法的不完备性,早先采用的某些垃圾收集算法就不能保证100%攉到所有的废弃内存。当焉着垃圾攉法的不断改q以?qing)Ygq行效率的不断提升,q些问题都可以迎刃而解?/span>
垃圾攉的算法分?/span>
Java语言规范没有明确地说?span>JVM使用哪种垃圾回收法Q但是Q何一U垃圾收集算法一般要?span>2件基本的事情Q(1Q发现无用信息对象;Q?span>2Q回收被无用对象占用的内存空_(d)使该I间可被E序再次使用?/span>
大多数垃圑֛收算法用了(jin)栚w(root set)q个概念Q所谓根集就量正在执行的JavaE序可以讉K的引用变量的集合(包括局部变量、参数、类变量)Q程序可以用引用变量访问对象的属性和调用对象的方法。垃圾收集首选需要确定从根开始哪些是可达的和哪些是不可达的,从根集可辄对象都是zd对象Q它们不能作为垃圾被回收Q这也包括从栚w间接可达的对象。而根集通过L路径不可辄对象W合垃圾攉的条Ӟ应该被回收。下面介l几个常用的法?/span>
1?nbsp;引用计数?/span>(Reference Counting Collector)
引用计数法是唯一没有使用栚w的垃圑֛收的法,该算法用引用计数器来区分存?gu)zd象和不再使用的对象。一般来_(d)堆中的每个对象对应一个引用计数器。当每一ơ创Z个对象ƈ赋给一个变量时Q引用计数器|ؓ(f)1。当对象被赋lQ意变量时Q引用计数器每次?span>1当对象出?jin)作用域?span>(该对象丢弃不再?span>)Q引用计数器?span>1Q一旦引用计数器?span>0Q对象就满?jin)垃圾收集的条g?/span>
Z引用计数器的垃圾攉器运行较快,不会(x)长时间中断程序执行,适宜地必?实时q行的程序。但引用计数器增加了(jin)E序执行的开销Q因为每ơ对象赋l新的变量,计数器加1Q而每ơ现有对象出?jin)作用域生,计数器?span>1?/span>
2?span>tracing法(Tracing Collector)
tracing法是ؓ(f)?jin)解军_用计数法的问题而提出,它用了(jin)栚w的概c(din)基?span>tracing法的垃圾收集器从根集开始扫描,识别出哪些对象可达,哪些对象不可达,q用某种方式标记可达对象Q例如对每个可达对象讄一个或多个位。在扫描识别q程中,Ztracing法的垃圾收集也UCؓ(f)标记和清?span>(mark-and-sweep)垃圾攉?span>.
3?span>compacting法(Compacting Collector)
Z(jin)解决堆碎片问题,Ztracing的垃圑֛收吸收了(jin)Compacting法的思想Q在清除的过E中Q算法将所有的对象Ud堆的一端,堆的另一端就变成?jin)一个相?c)I闲内存区,攉器会(x)对它Ud的所有对象的所有引用进行更斎ͼ使得q些引用在新的位|能识别原来 的对象。在ZCompacting法的收集器的实CQ一般增加句柄和句柄表。
4?span>copying法(Coping Collector)
该算法的提出是ؓ(f)?jin)克服句柄的开销和解军_片的垃圑֛收。它开始时把堆分成 一个对?面和多个I闲面, E序从对象面为对象分配空_(d)当对象满?jin),Zcoping法的垃?攉׃栚w中扫描活动对象,q将每个 zd对象复制到空闲面(使得zd对象所占的内存?sh)间没有I闲z?span>)Q这L(fng)闲面变成?jin)对象面Q原来的对象面变成了(jin)I闲面,E序?x)在新的对象面中分配内存?/span>
一U典型的Zcoping法的垃圑֛收是stop-and-copy法Q它?yu)堆分成对象面和I闲区域面,在对象面与空闲区域面的切换过E中Q程序暂停执行?/span>
5?span>generation法(Generational Collector)
stop-and-copy垃圾攉器的一个缺h攉器必d制所有的zd对象Q这增加?jin)程序等待时_(d)q是coping法低效的原因。在E序设计中有q样的规律:(x)多数对象存在的时间比较短Q少数的存在旉比较ѝ因此,generation法堆分成两个或多个,每个子堆作ؓ(f)对象的一?span>(generation)。由于多数对象存在的旉比较短,随着E序丢弃不用的对象Q垃圾收集器从最q轻的子堆中攉q些对象。在分代式的垃圾攉器运行后Q上ơ运行存?gu)zM来的对象Ud下一最高(sh)的子堆中Q由于老一代的子堆不会(x)l常被回Ӟ因而节省了(jin)旉?/span>
6?span>adaptive法(Adaptive Collector)
在特定的情况下,一些垃圾收集算法会(x)优(sh)其它法。基?span>Adaptive法的垃圾收集器是监控当前堆的使用情况Qƈ选择适当法的垃圾收集器?/span>
透视Java垃圾回收
1、命令行参数透视垃圾攉器的q行
2、?span>System.gc()可以不管JVM使用的是哪一U垃圑֛收的法Q都可以hJava的垃圑֛收。在命o(h)行中有一个参?span>-verbosegc可以查看Java使用的堆内存的情况,它的格式如下Q?span>
java -verbosegc classfile
可以看个例子Q?/span>
class TestGC
{
public static void main(String[] args)
{
new TestGC();
System.gc();
System.runFinalization();
}
}
在这个例子中Q一个新的对象被创徏Q由于它没有使用Q所以该对象q速地变(sh)ؓ(f)可达Q程序编译后Q执行命令:(x) java -verbosegc TestGC 后结果ؓ(f)Q?span>
[Full GC 168K->97K(1984K), 0.0253873 secs]
机器的环境ؓ(f)Q?span>Windows 2000 + JDK
2?span>finalizeҎ(gu)透视垃圾攉器的q行
?span>JVM垃圾攉器收集一个对象之?Q一般要求程序调用适当的方法释放资源,但在没有明确释放资源的情况下Q?span>Java提供?jin)缺省机制来l止化该对象?j)释放资源,q个Ҏ(gu)是finalizeQ)(j)。它的原型ؓ(f)Q?span>
protected void finalize() throws Throwable
?span>finalize()Ҏ(gu)q回之后Q对象消失,垃圾攉开始执行。原型中?span>throws Throwable表示它可以抛ZQ何类型的异常?span>
之所以要使用finalize()Q是׃有时需要采取与Java的普通方法不同的一U方法,通过分配内存来做一些具?span>C风格的事情。这主要可以通过"固有Ҏ(gu)"来进行,它是?span>Java里调用非JavaҎ(gu)的一U方式?span>C?span>C++是目前唯一获得固有Ҏ(gu)支持的语a。但׃它们能调用通过其他语言~写的子E序Q所以能够有效地调用M东西。在?span>Java代码内部Q也许能调用C?span>malloc()pd函数Q用它分配存储空间。而且除非调用?span>free()Q否则存储空间不?x)得到释放,从而造成内存"漏洞"的出现。当?dng)?span>free()是一?span>C?span>C++函数Q所以我们需要在finalize()内部的一个固有方法中调用它。也是说我们不能过多地使用finalize()Q它q不是进行普通清除工作的理想场所?span>
在普通的清除工作中,为清除一个对象,那个对象的用户必d希望q行清除的地点调用一个清除方法。这?span>C++"破坏?span>"的概늨有抵触。在C++中,所有对象都?x)破坏(清除Q。或者换句话_(d)所有对象都"应该"破坏。若?span>C++对象创徏成一个本地对象,比如在堆栈中创徏Q在Java中是不可能的Q,那么清除或破坏工作就?x)?span>"l束花括?span>"所代表的、创个对象的作用域的末尾q行。若对象是用new创徏的(cM?span>JavaQ,那么当程序员调用C++?span>delete命o(h)ӞJava没有q个命o(h)Q,׃(x)调用相应的破坏器。若E序员忘C(jin)Q那么永q不?x)调用破坏器Q我们最l得到的是一个内?span>"漏洞"Q另外还包括对象的其他部分永q不?x)得到清除?span>
相反Q?span>Java不允许我们创建本圎ͼ局部)(j)对象--无论如何都要使用new。但?span>Java中,没有"delete"命o(h)来释攑֯象,因ؓ(f)垃圾攉器会(x)帮助我们自动释放存储I间。所以如果站在比较简化的立场Q我们可以说正是׃存在垃圾攉机制Q所?span>Java没有破坏器。然而,随着以后学习(fn)的深入,׃(x)知道垃圾攉器的存在q不能完全消除对破坏器的需要,或者说不能消除对破坏器代表的U机制的需要(而且l对不能直接调用finalize()Q所以应量避免用它Q。若希望执行除释攑֭储空间之外的其他某种形式的清除工作,仍然必须调用Java中的一个方法。它{h(hun)?span>C++的破坏器Q只是没后者方ѝ?span>
下面q个例子向大家展CZ(jin)垃圾攉所l历的过E,q对前面的陈q进行了(jin)ȝ?/span>
class Chair {
static boolean gcrun = false;
static boolean f = false;
static int created = 0;
static int finalized = 0;
int i;
Chair() {
i = ++created;
if(created == 47)
System.out.println("Created 47");
}
protected void finalize() {
if(!gcrun) {
gcrun = true;
System.out.println("Beginning to finalize after " + created + " Chairs have been created");
}
if(i == 47) {
System.out.println("Finalizing Chair #47, " +"Setting flag to stop Chair creation");
f = true;
}
finalized++;
if(finalized >= created)
System.out.println("All " + finalized + " finalized");
}
}
public class Garbage {
public static void main(String[] args) {
if(args.length == 0) {
System.err.println("Usage: \n" + "java Garbage before\n or:\n" + "java Garbage after");
return;
}
while(!Chair.f) {
new Chair();
new String("To take up space");
}
System.out.println("After all Chairs have been created:\n" + "total created = " + Chair.created +
", total finalized = " + Chair.finalized);
if(args[0].equals("before")) {
System.out.println("gc():");
System.gc();
System.out.println("runFinalization():");
System.runFinalization();
}
System.out.println("bye!");
if(args[0].equals("after"))
System.runFinalizersOnExit(true);
}
}
上面q个E序创徏?jin)许?span>Chair对象Q而且在垃圾收集器开始运行后的某些时候,E序?x)停止创?span>Chair。由于垃圾收集器可能在Q何时间运行,所以我们不能准知道它在何时启动。因此,E序用一个名?span>gcrun的标记来指出垃圾攉器是否已l开始运行。利用第二个标记fQ?span>Chair可告?span>main()它应停止对象的生成。这两个标记都是?span>finalize()内部讄的,它调用于垃圾攉期间。另两个static变量--created以及(qing)finalized--分别用于跟踪已创建的对象数量以及(qing)垃圾攉器已q行完收ַ作的对象数量。最后,每个Chair都有它自qQ非staticQ?span>int iQ所以能跟踪?jin)解它具体的~号是多。编号ؓ(f)47?span>Chairq行完收ַ作后Q标C(x)设ؓ(f)trueQ最l结?span>Chair对象的创E。(关于q个例子的更具体的分析和说明请参看?span>Java~程思想》的W四章)(j)
关于垃圾攉的几点补?/strong>
l过上述的说明,可以发现垃圾回收有以下的几个特点Q?span>
Q?span>1Q垃圾收集发生的不可预知性:(x)׃实现?jin)不同的垃圾攉法和采用?jin)不同的收集机Ӟ所以它有可能是定时发生Q有可能是当出现pȝI闲CPU资源时发生,也有可能是和原始的垃圾收集一P{到内存消耗出现极限时发生Q这与垃圾收集器的选择和具体的讄都有关系?span>
Q?span>2Q垃圾收集的_性:(x)主要包括2 个方面:(x)Q?span>aQ垃圾收集器能够_标记zȝ的对象;Q?span>bQ垃圾收集器能够_地定位对象之间的引用关系。前者是完全地回收所有废弃对象的前提Q否则就可能造成内存泄漏。而后者则是实现归q和复制{算法的必要条g。所有不可达对象都能够可靠地得到回收Q所有对象都能够重新分配Q允许对象的复制和对象内存的~ƈQ这样就有效地防止内存的支离破碎。(3Q现在有许多U不同的垃圾攉器,每种有其法且其表现各异Q既有当垃圾攉开始时停止应用程序的q行Q又有当垃圾攉开始时也允许应用程序的U程q行Q还有在同一旉垃圾攉多线E运行?span>
Q?span>4Q垃圾收集的实现和具体的JVM 以及(qing)JVM的内存模型有非常紧密的关pR不同的JVM 可能采用不同的垃圾收集,?span>JVM 的内存模型决定着?span>JVM可以采用哪些cd垃圾攉。现在,HotSpot pdJVM中的内存pȝ都采用先q的面向对象的框架设计,q得该pdJVM都可以采用最先进的垃圾收集?span>
Q?span>5Q随着技术的发展Q现代垃圾收集技术提供许多可选的垃圾攉器,而且在配|每U收集器的时候又可以讄不同的参敎ͼq就使得Ҏ(gu)不同的应用环境获得最优的应用性能成ؓ(f)可能?span>
针对以上特点Q我们在使用的时候要注意Q?span>
Q?span>1Q不要试囑֎假定垃圾攉发生的时_(d)q一切都是未知的。比如,Ҏ(gu)中的一个(f)时对象在Ҏ(gu)调用完毕后就变成?jin)无用对象,q个时候它的内存就可以被释放?span>
Q?span>2Q?span>Java中提供了(jin)一些和垃圾攉打交道的c,而且提供?jin)一U强行执行垃圾收集的Ҏ(gu)--调用System.gc()Q但q同h个不定的方法?span>Java 中ƈ不保证每ơ调用该Ҏ(gu)׃定能够启动垃圾收集,它只不过?x)?span>JVM发出q样一个申P到底是否真正执行垃圾攉Q一切都是个未知数?span>
Q?span>3Q挑(xi)选适合自己的垃圾收集器。一般来_(d)如果pȝ没有Ҏ(gu)和苛ȝ性能要求Q可以采?span>JVM的缺省选项。否则可以考虑使用有针Ҏ(gu)的垃圾攉器,比如增量攉器就比较适合实时性要求较高的pȝ之中。系l具有较高的配置Q有比较多的闲置资源Q可以考虑使用q行标记/清除攉器?span>
Q?span>4Q关键的也是难把握的问题是内存泄漏。良好的~程?fn)惯和严谨的~程态度永远是最重要的,不要让自q一个小错误D内存出现大漏z?span>
Q?span>5Q尽早释放无用对象的引用。大多数E序员在使用临时变量的时候,都是让引用变量在退出活动域(scope)后,自动讄?span>nullQ暗C垃圾收集器来收集该对象Q还必须注意该引用的对象是否被监听,如果有,则要L监听器,然后再赋I倹{?span>
l束?/strong>
一般来_(d)Java开发h员可以不重视JVM中堆内存的分配和垃圾处理攉Q但是,充分理解Java的这一Ҏ(gu)可以让我们更有效地利用资源。同时要注意finalize()Ҏ(gu)?span>Java的缺省机Ӟ有时为确保对象资源的明确释放Q可以编写自qfinalizeҎ(gu)?/span>