Java EE應用中的性能問題解決方案 — 第一部分 內存溢出的解決辦法(C)

聲明:本文禁止未經本人同意的任何形式轉載!如有轉載需求,可與本人通過個人資料中的電子郵箱聯繫。對於未經同意的轉載,本人將保留進一步行動的權利! 

 假內存泄露

有一些情況表現得很像內存泄露,但實際上並不是的。以下情況/地方有可能導致這樣的錯誤判斷:
  • 過早下結論
  • 會話
  • 永生代異常
 
下面我們就來一一討論一下。
 
 
過早下結論
在查找內存泄露的過程中,重要的是要適時掌握觀察和分析堆的情況。其中的問題在於,因爲一些長期生存的對象需要被保留在堆中,所以必須要等到堆的狀態比較穩定的情況下(只保留了核心對象的情況)才能不被假象矇蔽。所以需要當應用達到穩定狀態後才能執行對堆的分析。
 
檢查是否過早對堆進行分析的辦法是在記錄了一次堆的情況後的一段時間內(比如幾個小時)不斷對堆的情況進行記錄分析。如果堆不斷增長的趨勢已經結束,那麼即可對堆進行記錄。如果堆還有持續上升的趨勢,則可對已有的內存情況進行分析並做出判斷。
 
會話
我們在前面說過,內存泄露可能會出現在Web請求的階段。但在Web請求階段,對象可能被存儲在少數明確的一些地方,包括:
  • 頁面範圍(Page)
  • 請求範圍(Request)
  • 會話範圍(Session)
  • 應用範圍(Application)
  • 靜態變量(static)
  • 長期生存的類變量,例如本身就在servlet中的那些
 
在JSP中,當頁面完成後,JSP裏本身創建的變量是符合垃圾收集的條件的,這些變量的生存週期是在一個頁面範圍內。
 
屬性(attribute)和參數(parameter)從Web服務器傳送到應用服務器,屬性也可在servlet和JSP中通過HttpServletRequest對象傳遞。HttpServletRequest對象作爲一種通信機制服務於動態web層上的不同的組件中,但當請求完成且關閉與用戶socket連接時,servlet容器就將存儲在HttpServletRequest對象中的所有變量的空間回收。這些變量的生存週期是在一個請求的範圍內。
 
由於HTTP是一個無狀態的協議,即意味着客戶端請求服務器,服務器應答客戶端後,通信即中止了,會話狀態將不會得到保留。因此,我們需要一種機制能進行狀態的保留,這就是會話(session)。屬性和參數可根據不同的用戶來存儲到不同的HttpSession對象中,他們可以被應用中的servlet或JSP訪問。這樣,就可以將諸如登錄、購物車等這樣的信息添加到會話中,不同用戶的狀態就得到了保留。對於無狀態的協議,總是客戶端先提出對服務器的訪問,這就需要讓服務器知道兩次訪問的最大間隔時間,以便保存會話或放棄保存會話。這就使session time-out,可通過應用服務器配置。所以,除非用戶主動移除會話中的對象或者會話失效,會話中的對象就會一直駐留在服務器上。
 
Session是在用戶這個級別上管理對象的,ServletContext則是在應用這個級別上管理對象的。ServletContext之所以被稱爲是應用範圍的,就是因爲可以在其它servlet和JSP頁面上共享servlet的ServletContext或JSP的application對象。ServletContext是最主要的應用配置信息和應用級別數據的緩存地點,例如數據JNDI等信息。
 
如果數據沒有保存在這些範圍內的對象中,還有可能保留在靜態變量和長期生存的類變量中。
 
靜態變量在JVM中以每個類一個的級別進行存儲,且不需要堆中存在類的實例。所有類實例共享相同的靜態變量值,所以在一個對象中改變靜態變量的值會影響到其它對象中的值。所以,如果應用將對象保存在靜態變量中並將該變量賦爲null的話,該靜態對象並不會被JVM回收。這些靜態對象是內存泄露的主要發生地。
 
最後,我們將一些對象加入了像servlet之類的長期生存的類中作爲內部數據結構或成員變量。當servlet被創建並被加載到內存,它只有一個實例在內存中,多個線程通過相應的配置來訪問servlet實例。如果在init()方法中加載配置信息,將其存入類的變量中,並在服務請求的時候讀取這些信息,這就確保了所有的實例都訪問到了同樣的信息。有時候有的應用使用servlet類變量來保存頁面緩存的數據。這可能放錯了地方。如果考慮使用cache的話,放到集成的第三方的緩存中可能是比較好的選擇。
當頁面或者請求範圍的變量保持着對對象的引用時,它們會被自動清理掉。如果是會話級別變量中保存着對象引用的話,就沒有那麼容易了。
未完待續……
聲明:本文禁止未經本人同意的任何形式轉載!如有轉載需求,可與本人通過個人資料中的電子郵箱聯繫。對於未經同意的轉載,本人將保留進一步行動的權利!
發佈了13 篇原創文章 · 獲贊 0 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章