Java的內存回收——內存管理小技巧

4、內存管理小技巧

4、1 儘量使用直接量

       當需要使用字符串,還有Byte、Short、Integer、Long、Float、Double、Boolean、Character包裝類的實例時,程序不應該採用new的方式來創建對象,而應該直接採用直接量來創建它們。
       例如,程序需要"hello"字符串,應該採用如下代碼:
     String str = "hello";
      上面方式會創建一個"hello"字符串,而且JVM的字符串緩存池還會緩存這個字符串。但是如果程序使用如下代碼:
     String str = new String("hello");
      此時程序同樣創建了一個緩存在字符串緩存池中的"hello"字符串。除此之外,str所引用的String對象底層還包含了一個char[]數組,這個char[]數組裏依次存放了h、e、l、l、o等字符串。

4、2 使用StringBuilder和StringBuffer進行字符串連接

       String、StringBuilder、StringBuffer都可以代表字符串,其中String代表字符序列不可變的字符串,而StringBuilder、StringBuffer都代表字符串序列可變的字符串。
       如果程序使用多個String對象進行字符串連接運算,在運行時將生成大量的臨時字符串,這些字符串會保存在內存中從而導致程序性能下降。

4、3 儘早釋放無用對象的引用

       大部分時候,方法的局部引用變量所引用的對象會隨着方法的結束而變成垃圾,因爲局部變量的生存期限很短,當方法運行結束時,該方法內的局部變量就結束了生存期限。因此,大部分時候程序無須將局部變量顯示設爲null,但是有時候涉及到消耗內存的部分則需要顯示的設置爲null。

4、4 儘量少用靜態變量

       從理論上來說,Java對象何時被回收由垃圾回收機制決定,對程序員來說是不確定的。由於垃圾回收機制判斷一個對象是否是垃圾的唯一標準就是該對象是否有引用變量引用它,因此推薦儘早釋放對象的引用。
       最壞的情況是,某個對象被static變量所引用,那麼垃圾回收機制通常是不會回收這個對象所佔的內存。示例如下:
     class Person {
         static Object obj = new Object();
     }
       對於上面的Object對象而言,只要obj變量還引用到它,它就不會被垃圾回收機制所回收。obj變量是Person類的靜態變量,因此它的生命週期與Person類同步。在Person類不被卸載的情況下,Person類對應的Class對象會常駐內存,直到程序運行結束。因此,obj所引用的Object對象一旦創建,也會常駐內存,直到程序運行結束。
提示:根據分代回收機制,JVM會將程序中Person類的信息存入Permanent代。也就是說,Person類、obj引用變量都將存在Permanent代裏,這將導致obj對象一直有效,從而使得obj所引用的Object得不到回收。

4、5 避免在經常調用的方法、循環中創建Java對象

       經常調用的方法和循環有一個共同的特徵:這些代碼段會被多次重複調用。
     public class Test {
        public static void main(String[] args) {
           for(int i = 0 ; i < 10 ; i ++) {
              Object obj = new Object();
              //執行其他操作...
           }
        }
     }
       上面代碼在循環中創建10個Object對象,雖然上面程序中的obj變量都是代碼塊的局部變量,當循環執行結束時這些局部變量都會失效,但由於這段循環導致Object對象會被創建10次,因此係統需要不斷地爲10個對象分配內存空間並執行初始化操作。這10個對象的生存時間並不長,接下來系統又需要回收它們所佔用的空間。在這種不斷的分配、回收操作中,程序的性能受到巨大的影響。

4、6 緩存經常使用的對象

       如果有些對象需要被經常使用,則可以考慮把這些對象用緩存池保存起來,這樣當下次需要時就可以直接拿出這些對象來使用。典型的緩存就是數據連接池,數據連接池裏緩存了大量的數據庫連接,每次程序需要訪問數據庫時都可以直接取出數據庫連接。
       除此之外,如果系統中還有一些常用的基礎信息,比如信息化信息裏包含的員工信息等。實現緩存時通常由兩種方式。
  • 使用HashMap進行緩存。
  • 直接使用某些開源項目。
       如果直接使用HashMap進行緩存,程序員需要手動控制HashMap容器裏的key-value對不至於太多,因此當key-value對太多時將導致HashMap佔用過大的內存,從而導致系統性能下降。如果使用一些開源的緩存項目進行緩存,這些緩存項目都會主動分配一個具有一定大小的緩存容器,再按照一定算法來淘汰容器中不需要繼續緩存的對象。這樣一方面開源通過緩存已用過的對象來提高系統的運行效率,另一方面又可以控制緩存容器的無限制擴大,從而減少系統的內存佔用。對於這種開源的緩存實現有很多選擇,如OSCache、Ehcache等,大多實現了FIFO、MRU等常見的緩存算法。

4、7 儘量不要使用finalize方法

       在一個對象失去引用之後,垃圾回收器準備回收該對象之前,垃圾回收機制會先調用該對象的finalize()方法來執行資源清理。出於這種考慮,可能會考慮使用finalize()方法來進行資源清理。
       實際上,將資源清理放在finalize()方法中完成不是一個好選擇,在垃圾回收器本身已經嚴重製約應用程序性能的情況下,如果再選擇使用finalize()方法進行資源清理,無疑是火上澆油的行爲,這將導致垃圾回收器負擔更大,導致程序運行效率更差。

4、8 考慮使用SoftReference

       當程序需要創建長度很大的數組時,可以考慮使用SoftReference來包裝數組元素,而不是直接讓數組元素來引用對象。SoftReference是一個很好的選擇:當內存足夠時,它的功能等同於普通引用;當內存不夠時,會犧牲自己,釋放軟引用所引用的對象。
       使用軟引用引用對象時不要忘記引用的不確定性。程序通過軟引用所獲取的對象有可能爲null。當系統內存緊張時,SoftReference所引用的Java對象將被釋放。由於通過SoftReference獲取的對象可能爲null,因此應用程序取出SoftReference所應用的Java對象之後,應該顯示判斷該對象是否爲null;當該對象爲null時,應重建該對象。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章