一、概述
對于代碼級的優化,不管用哪種程序語言編程,首先都應該注意編碼規范和風格。不同的公司或者團隊以至程序員個人都有自己的編碼風格,但目的是讓程序代碼可讀、簡潔、高效、易于重用。養成良好的編碼習慣是每個程序員的必需的。最開始,我們可以針對自己編寫的代碼進行自己檢查,看看有沒有什么改進的地方,包括注釋是否適當,命名是否恰當,程序是否最優化等等,然后可以進行同行評審一下,針對意見進行思考,改進自己編寫代碼。如果公司有條件,譬如有專門的測試規范、技術配置與管理等等,可以利用他們提供的方法與工具進行單元測試與代碼檢查。譬如用
jtest
工具,可以根據編碼規范編制一套規則,用它來檢測自己的程序是否符合規范。
在養成良好的編碼習慣與編碼規范之后,我們接下來要針對程序的本身進行優化。首先檢查自己的代碼是不是使用的較優的算法,在設計上是否符合邏輯,有沒有更好實現方式。這一點可能有點難度,隨著編程的經驗與思考的程度增加,會提高自己程序設計的能力。這些方面可以多看點這方面的書,譬如《代碼大全
第二版》等等。
最后,針對程序設計語言的本身特點進行優化,包括變量的創建、內存的管理等等。譬如在
JAVA
中,應該盡可能少的創建對象。
另外一個方面,我們可以從大師級那里去經,閱讀大師寫的代碼。參看一些前人的經驗,特別是設計模式。設計模式應該可以說是精華的提研,但同時不要受其束縛,當自己感覺有些不同的時候,要大膽創新。
二、
Java
程序的設計風格
跳過閱讀,詳細風格參見本目錄下的《軟件編程規范—
Java.doc
》;
如果測試部能根據編碼規范定義規則對代碼進行單元測試,那就更好了。
三、內存管理
1.
垃圾回收
GC, Garbage Collection
,垃圾回收機制,一個對象創建后被放置在
JVM
的堆內存中,
當永遠不再引用這個對象時,它將被
JVM
在堆內存中回收。
堆內存(
Heap
),堆內存在
JVM
啟動的時候被創建,堆內存中存儲的對象可以被
JVM
自動回收,但不能通過其他外部手段回收。
Heap
通常劃分兩個區域:新對象區域和老對象區域新對象區的對象超過生命周期,會轉入到老對象區域,并且標記為垃圾對象,垃圾回收與對象的生命周期是緊緊聯系在一起的。
優化:
(
1
)最好不要手動調用
GC
(
System.gc()
),推薦使用
obj = null
的方式來提醒
JVM
來調用
GC
Object obj = new Object();
???? …?? //
使用
obj = null ;
|
(
2
)
JVM
內存參數調整
???? JVM
的默認內存大小為
-
Xms,
-
Xmx
一般設為同樣大小。
800m
-
Xmn
是將
NewSize
與
MaxNewSize
設為一致。
320m
-
XX:PerSize 64m
-
XX:NewSize 320m
此值設大可調大新對象區,減少
Full GC
次數
-
XX:MaxNewSize 320m
-
XX:NewRato NewSize
設了可不設。
4
-
XX: SurvivorRatio 4
-
XX:userParNewGC
可用來設置并行收集
-
XX:ParallelGCThreads
可用來增加并行度
4
-
XXUseParallelGC
設置后可以使用并行清除收集器
-
XX
:
UseAdaptiveSizePolicy
與上面一個聯合使用效果更好,利用它可以自動優化新域大小以及救助空間比值
|
Ps
:具體性能最優參數,可以通過性能測試把參數測試出來,相關性能測試方法與工具使用可以參考《
J2EE
性能測試》。
2. JVM
的生命周期
??????
我們分析期生命周期的原因在于,我們可以觀察每個階段是不是有優化的可能性,從而進行優化。
(
1
)創建階段:分配存儲空間
-- >
構造對象
-- >
遞歸調用超類構造函數
-- >
象實例初始化與變量的初始化
-- >
行構造方法體
優化:
根據對象創建的應用規則進行優化:
a.??????
避免在循環體內創建對象,即使該對象占用的內存空間不大,應該采用如下方式
Object obj = null;
for( int i=0 ; i<1000 ; ++i ) {
obj = new Object();
?… …
}
|
b.??????
不要一個對象初始化多次
Object obj = new Object();
//
這樣寫不正確,應該聲明為空,在使用的時候再創建實例
//
正確寫法
Object obj = null;
if ( … ) {
} |
c.??????
盡量及時使對象符合垃圾回收的標準
譬如使用
obi = null;
或者調用規則的方法,如
servlet
中
destroy()
方法。
d.??????
不要采用過深的繼承層次
因為繼承類的初始化會調用基類的默認構造函數,導致大量的開銷。一般繼承
結構不宜超過
3
層,另外,推薦使用接口。
e.??????
訪問本地變量優于訪問類中的變量
譬如
String
對象類型,如果使用
String.length()
方法超過兩次,我們應該考慮
使用一個變量來替代,
int temp = String.length();
(
2
)應用階段:
??????
在應用階段,系統至少維護著對象的強引用。
??????
強應用(
Strong Reference
):指
JVM
內存管理器從根引用集合(
Root Set
)出發遍尋堆中所有到達對象的路徑。
軟應用(
Soft Reference
):具有較強的引用功能。可以用于實現一些常用的資源的緩存,實現
Cache
的功能,保證最大限度的使用內存而不引起
Out Of Memory
。軟引用技術的引進使
Java
應用可以更好的管理內存,穩定系統,防止系統內存溢出。軟引用使用方式:
A a = new A();
……
//
使用完
a
,將它設置為
soft
引用類型,并且釋放強引用
;
SoftReference sr = new SoftReference(a);
a = null;
?????? …
//
下次使用
if( sr != null) {
?????? a = sr.get();
}else{
?????? //GC
由于低內存,已釋放
a
,因此需要重新裝載
?????? a = new A();
??? sr = new SoftRerence(a);
} |
弱引用(
Weak Reference
):與
soft
引用對象不同之處在于:
GC
在進行回收時,需要通過算法檢查是否回收
Soft
引用對象,而對于
Weak
對象,
GC
總是進行回收。
虛引用(
Phantom Reference
):輔助
finalize
函數的使用。
(
3
)其他階段
不可視階段
不可到達階段
可收集階段、終結階段與釋放階段,
3.
構造函數與
Finalize
函數
構造函數會在類初始化實例的時候將會被執行,因此,我們在設計類的時候盡可能的避免在類的默認構造函數中創建、初始化大量的對象。
finalize
,類似
C++
中析構函數
4.
數組的創建
創建的時候,一般我們盡可能的使用隱式創建:
int [] intArray = obj.getIntArray();
如果碰到占用內存空間比較大的時候,我們通過軟引用技術來應用數組。
5.
共享靜態變量存儲空間
靜態變量可以節約大量的內存開銷,使用情況:
(1)??????
變量做所包含的對象體積較大,占用內存較多
(2)??????
變量所包含的對象生命周期長
(3)??????
變量所包含的數據穩定
(4)??????
該類的對象實例有對該變量所包含對象的共享需求
6.
對象重用
緩存對象的應用,對象池(
ObjectPool
)
,
通過對其所保存對象的共享和重用,縮減了應用線程反復重建、裝載對象所需要的時間,并且避免頻繁的垃圾回收帶來的巨大開銷。
譬如數據庫的連接池,對一個數據庫連接池詳細研究
參見文章《數據庫連接池技術》
7.
瞬間值
實現
Java.lang.Serializable
接口,具體使用參見其
API
。
8.Java
程序設計其他經驗
(1)
盡早釋放無用引用對象,
obj = null ;
(2)
盡量少用
finalize
函數
(3)
如果經常使用圖片,可以使用
soft
應用類型
(4)
注意集合數據類型,這些對
GC
來說,回收更復雜
??
注意一些全局變量,或者靜態變量容易引起懸掛對象,造成對象浪費
(5)
盡量避免在類的默認構造器中創建、初始化大量的對象
(6)
盡量避免強制系統調用
GC
(
System.gc()
)
(7)
盡量避免顯式申請數組空間
(8)
盡量在做
RMI
類應用開發時使用瞬間值(
transient
)變量
(9)
盡量在合適的場合下使用對象池技術以提高系統性能
參考資料:
?《Java優化編程》?