1. 程式人生 > 其它 >Java 虛擬機器記憶體溢位問題和解決方法

Java 虛擬機器記憶體溢位問題和解決方法

什麼是記憶體溢位

  • 記憶體溢位是指應用系統中存在無法回收的記憶體或使用的記憶體過多,最終使得程式執行要用到的記憶體大於虛擬機器能提供的最大記憶體。
  • Java的記憶體管理就是物件的分配和釋放問題
  • 在Java中,記憶體的分配是由程式完成的,而記憶體的釋放是由垃圾收集器(Garbage Collection,GC)完成的,程式設計師不需要通過呼叫GC函式來釋放記憶體,因為不同的JVM實現者可能使用不同的演算法管理GC,有的是記憶體使用到達一定程度時,GC才開始工作,也有定時執行的,有的是中斷式執行GC。但GC只能回收無用並且不再被其它物件引用的那些物件所佔用的空間。Java的記憶體垃圾回收機制是從程式的主要執行物件開始檢查引用鏈,當遍歷一遍後發現沒有被引用的孤立物件就作為垃圾回收。

記憶體溢位的原因

  • 記憶體中載入的資料量過於龐大
  • 集合類中有物件的引用,使用完後未被清空
  • 程式碼中存在死迴圈或迴圈產生過多重複的物件
  • 啟動引數記憶體值設定過小

解決辦法

  • 修改JVM啟動引數,直接增加記憶體。
    JVM預設可以使用的記憶體為64M,Tomcat預設可以使用的記憶體為128MB。這對於其他大型引用絕對是不夠的
  • 檢查錯誤日誌,檢視“OutOfMemory”錯誤前是否有其它異常或錯誤。
  • 對程式碼進行走查和分析,
    檢查程式碼中是否有死迴圈或遞迴呼叫。
    檢查是否有大迴圈重複產生新物件實體。
    檢查對資料庫查詢中,是否有一次獲得全部資料的查詢,而沒有使用分頁。
    檢查List、MAP等集合物件是否有使用完後,未清除的問題。List、MAP等集合物件會始終存有對物件的引用,使得這些物件不能被GC回收。
  • 儘早釋放無用物件的引用。好的辦法是使用臨時變數的時候,讓引用變數在退出活動域後,自動設定為 null ,暗示垃圾收集器來收集該物件,防止發生記憶體洩露。
    對於仍然有指標指向的例項, jvm 就不會回收該資源 , 因為垃圾回收會將值為 null 的物件作為垃圾,提高 GC 回收機制效率;
  • 我們的程式裡不可避免大量使用字串處理,避免使用 String ,應大量使用 StringBuffer ,每一個 String 物件都得獨立佔用記憶體一塊區域;
    String str = “aaa”;
    String str2 = “bbb”;
    String str3 = str + str2;// 假如執行此次之後 str ,str2 以後再不被呼叫 , 那它就會被放在記憶體中等待 Java 的 gc 去回收 , 程式內過多的出現這樣的情況就會報上面的那個錯誤。
  • 儘量少用靜態變數,因為靜態變數是全域性的, GC 不會回收的;
  • 避免集中建立物件尤其是大物件, JVM 會突然需要大量記憶體,這時必然會觸發 GC 優化系統記憶體環境;顯示的宣告陣列空間,而且申請數量還極大。
    比如:
    有個excel檔案上傳的功能,excel內容有非常大,每次上傳都導致jvm需要大量的記憶體。
  • 儘量運用物件池技術以提高系統性能;生命週期長的物件擁有生命週期短的物件時容易引發記憶體洩漏,例如大集合物件擁有大資料量的業務物件的時候,可以考慮分塊進行處理,然後解決一塊釋放一塊的策略。
  • 不要在經常呼叫的方法中建立物件,尤其是忌諱在迴圈中建立物件。可以適當的使用 hashtable , vector 建立一組物件容器,然後從容器中去取那些物件,而不用每次 new 之後又丟棄
  • 一般都是發生在開啟大型檔案或跟資料庫一次拿了太多的資料,造成 Out Of Memory Error的狀況,這時就大概要計算一下資料量的最大值是多少,並且設定所需最小及最大的記憶體空間值。