今天閒來沒事在日誌中瞟見了個OutOfMemoryError錯誤,不禁得想到前一段時間看到一篇面經裏問到Java中是否有內存泄露,這個好久之前是留意過的,大致記得內存溢出和內存泄露是不一樣的,至於各自都有哪些狀況,那個...額....忘了...。好吧,記憶力一貫很差,忘就忘了,那就再總結一遍吧。翻了下收藏的博客,回顧了下即是想起了了~.~。看起來一切很美好,可是其中的一個例子忽然使我困惑了:java
public class TestDemo { static Test[] tests = new Test[3]; public static void main(String[] args) { Test t = new Test("test1"); tests[0] = t; //將t置爲null,看起來彷佛咱們已經釋放建立的對象,當下次gc時其將被回收 t = null; //那麼咱們打印下test[0]看看 System.out.println(tests[0]); } }
這是個示例內存泄露的例子,該例子十分典型,幾乎全部內存泄露的示例都與此相似,做爲javaer每每以爲理所應當。然而做爲一個學習C++入行(學的很爛),並一直把引用當指針看的javaer難免以爲有些疑惑:t是對象的引用,這裏能夠看作指向對象的指針,那麼test[0]=t,按理說應該是把t指針賦值給test[0],算是地址傳遞吧,那個t指向null以後,test[0]應該也指向null了啊。
看起來彷佛有點道理,然而當了解了java的引用以後,發現吧指針等同於引用是有一些問題的。
學習
java中的引用究竟是什麼呢,簡單點說,引用就是存在棧區的一種特定類型的數據,其存儲着對象實例在堆區的地址,其特色以下:
spa
從定義看起來彷佛仍是區分不出來引用到底和指針有什麼區別,那麼請注意上邊紅字,java爲了屏蔽對內存直接操做,對對象的實際內存地址進行了包裝,從而使引用中的值只能用來找對象,而沒法操做內存。這一點正是和指最大不一樣,C++中的指針就是一個真實的內存地址,能夠經過該地址把內存玩出十八般花樣。這點也說明了咱們經常把引用傳遞當成地址傳遞是錯誤的(雖然說實際效果差很少)。
指針
好吧,看了上邊一坨也許你並看不出個什麼,也許自己這塊有點繞,也許我說的不清楚,那麼咱們不如直接畫圖說明上邊那個例子到底發生了什麼(圖示畫的不必定和實際徹底一致,只爲說明問題),說不定你就明白了:
tests因爲是靜態變量,在類加載完就已經實例化了,其在堆內存中分配了長度爲3的空間,不過值都爲null。在建立t以後,t指向了堆內存中的對象:
日誌