Posted on 2009-06-06 09:38
thui 閱讀(614)
評論(1) 編輯 收藏 所屬分類:
java技術
java 語言是一門強大的語言,java的jdk為我們定義了很多的數據結構,方便了程序員的編碼,避免了重復造車,但是正是因為java語言本身為我們做了很多事情,使我們無法很少關心底層的東西,造成有時候我們寫的代碼雖然可以完成功能,但是卻不是最優(yōu)的,可能很耗資源。為此石頭邊學習邊研究,討論如何才能寫出高效的代碼。
首先要說的是java數據類型,我們知道java 語言是一門強大的語言,java的jdk為我們定義了很多的數據結構,方便了程序員的編碼,避免了重復造車,但是正是因為java語言本身為我們做了很多事情,使我們無法很少關心底層的東西,造成有時候我們寫的代碼雖然可以完成功能,但是卻不是最優(yōu)的,可能很耗資源。為此石頭邊學習邊研究,討論如何才能寫出高效的代碼。
首先要說的是java數據類型,我們知道java的數據類型有兩種:基本類型和引用類型,像int、byte、char、long等都屬于java的基本類型,它們不是對象,而所謂的引用類型通俗的說是指必須通過new方法才能得到的數據類型,說白了就是對象類型,那么基本類型和應用類型有什么區(qū)別呢?這個就需要探索java虛擬機內部是如何存儲兩種數據類型的,java的基本數據類型是存儲在棧上,而引用類型是存儲在堆上的,見下圖:
java的數據類型有兩種:基本類型和引用類型,像int、byte、char、long等都屬于java的基本類型,它們不是對象,而所謂的引用類型通俗的說是指必須通過new方法才能得到的數據類型,說白了就是對象類型,那么基本類型和應用類型有什么區(qū)別呢?這個就需要探索java虛擬機內部是如何存儲兩種數據類型的,java的基本數據類型是存儲在棧上,而引用類型是存儲在堆上的,見下圖:
java 語言是一門強大的語言,java的jdk為我們定義了很多的數據結構,方便了程序員的編碼,避免了重復造車,但是正是因為java語言本身為我們做了很多事情,使我們無法很少關心底層的東西,造成有時候我們寫的代碼雖然可以完成功能,但是卻不是最優(yōu)的,可能很耗資源。為此石頭邊學習邊研究,討論如何才能寫出高效的代碼。
首先要說的是java數據類型,我們知道java 語言是一門強大的語言,java的jdk為我們定義了很多的數據結構,方便了程序員的編碼,避免了重復造車,但是正是因為java語言本身為我們做了很多事情,使我們無法很少關心底層的東西,造成有時候我們寫的代碼雖然可以完成功能,但是卻不是最優(yōu)的,可能很耗資源。為此石頭邊學習邊研究,討論如何才能寫出高效的代碼。
首先要說的是java數據類型,我們知道java的數據類型有兩種:基本類型和引用類型,像int、byte、char、long等都屬于java的基本類型,它們不是對象,而所謂的引用類型通俗的說是指必須通過new方法才能得到的數據類型,說白了就是對象類型,那么基本類型和應用類型有什么區(qū)別呢?這個就需要探索java虛擬機內部是如何存儲兩種數據類型的,java的基本數據類型是存儲在棧上,而引用類型是存儲在堆上的,見下圖:
java的數據類型有兩種:基本類型和引用類型,像int、byte、char、long等都屬于java的基本類型,它們不是對象,而所謂的引用類型通俗的說是指必須通過new方法才能得到的數據類型,說白了就是對象類型,那么基本類型和應用類型有什么區(qū)別呢?這個就需要探索java虛擬機內部是如何存儲兩種數據類型的,java的基本數據類型是存儲在棧上,而引用類型是存儲在堆上的,見下圖:
如圖所示,StringBuffer是一個引用類型,它是存儲在堆上,str只是這個對象的一個引用,在C++語言里引用即是指針,指針即是對象的內存地址,str本身是一個存儲在棧上的基本類型。123是一個int類型,也是存儲在棧上的,很多同學要問了,棧和堆到底有什么不同?這里石頭給大家簡單的解釋下,我們不是常說函數調用需要壓棧出棧嗎?棧是線程私有的;而堆是全局的,所有線程共享的,棧的空間很小,所以用來存儲基本數據類型,堆很大,用來存儲對象這樣的大東西,由于堆是全局的共享的,可見堆是昂貴的,因為各個線程都要在它上面申請內存以存放對象,必然要求堆做好互斥和加鎖,這些消耗是很大的。所以我們在編寫代碼時必須考慮到這一點。石頭曾經做過一個題目,給你一個數字字母混合的字符串,寫出一個程序從中去除字母,保留數字。這個程序有很多種方法,但是歸納起來有兩種,一種是構造一個StringBuffer來把串中的數字連接;一種是用char數組來保存,經過測試后一種的效率高出前一種很多倍,為什么呢?就是因為第一種方法使用了對象StringBuffer,哪怕按照編程規(guī)范上說的優(yōu)化方法,構造StringBuffer時指定長度后性能提高也不大,第二種方法的優(yōu)勢在于char數組時基本類型,不需要在堆上進行內存的操作,節(jié)約了時間。
上面談了java基本數據類型,下面談談java的內存泄漏,內存泄漏到底是什么意思呢?有時候我們運行程序會出一個outofmemory的異常,這就是內存泄漏,這個異常是說內存不夠了,舉個bt的例子:
Vector v=new Vector();
for(int i=0;i<999999;i++)
{
v.add(new Date());
}
這段代碼運行肯定會拋出outofmemory的異常,像上面的bt代碼是故意制造內存泄漏,但是現實中我們編寫代碼時自己往往不會注意,運行久了便會出現內存溢出的錯誤,這種錯誤發(fā)生通常會發(fā)生在高速緩存,比如Vector、Map。
典型的算法如下所示:
1.檢查結果是否在高速緩存中,存在則返回結果;
2.如果結果不在,那么計算結果;
3.將結果放入高速緩存,以備將來的操作調用。
這個算法的問題(或者說潛在的內存泄漏)在最后一步。如果操作是分別多次輸入,那么存入高速緩存的內容將會非常大。很明顯這個方法不可取。
為了避免這種潛在的致命錯誤設計,程序就必須確定高速緩存在他所使用的內存中有一個上界。因此,更好的算法是:
1.檢查結果是否在高速緩存中,存在則返回結果;
2.如果結果不在,那么計算結果;
3.如果高速緩存所占空間過大,移除緩存中舊的結果;
4.將結果放入高速緩存,以備將來的操作調用。
所以我們編寫代碼時定義Vector、等緩存時一定記得指定一個初始化大小。剛才Vector的代碼如果象下面這樣寫就不會出錯了。
Vector v=new Vector(100);
public void add(Object obj)
{
if(v.size()<100)
{
v.add(obj);
}
}
當高速緩存不再使用時要記得把它設置為null,舉個例子:
Vector v=new Vector();
for(int i=0;i<999999;i++)
{
Object o=new Object();
v.add(o);
o=null;
}
這段代碼現new出對象o,然后加到vector中,最后又把對象設置為null,但是只是把對象的引用即指針置為null,Vector里對象還是在的,當不用vector時,要把vector設置為null才行