(一)深入理解Java虛擬機-虛擬機內存區域與內存溢出

作爲Java開發者,一般可能關注最多的就是堆內存(heap)和棧內存(stack),實際可分爲以下幾個區域:
這裏寫圖片描述
方法區(Method Area):與Java堆一樣,是各個線程共享內存區域,它存儲已被虛擬機加載的類信息 、常量、靜態變量、即時編譯器編譯後的代碼等數據。運行時常量池是方法區的一部分。
虛擬機棧(VM Stack): 線程私有的,生命週期與線程相同。每個方法執行的同時都會創建棧幀(Stack Fragme),用於存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。每個方法執行完成的過程對應着棧幀在虛擬機棧中入棧到出棧的過程。
本地方法棧(Native Method Stack):與虛擬機棧作用相似,只不過對應的是Nativie方法。
堆(Heap): 是虛擬機管理的內存最大的一塊,被所有線程共享。唯一目的就是存放對象實例,幾乎所有的對象都在這裏分配內存。Java堆是GC的主要區域。
程序計數器(Progress Counter Register):一塊較小的內存空間,線程私有,當前線程所執行的字節碼的行號指示器。

備註:直接內存(Direct Memory)雖不是虛擬機運行時數據的一部分,也不是虛擬機規範的內存區域,但是也會經常使用,就是我們 I/O操作。

內存溢出(OutOfMemoryError)從虛擬機角度分析可概括爲以下幾類:

  • 堆溢出
  • 棧溢出(虛擬機棧和本地方法棧)
  • 方法區和運行時常量池溢出
  • 直接內存溢出

只要GC Roots 可達,那麼這些對象就不會被回收。那麼可作爲GC Roots的對象主要是以下幾種:

  • 虛擬機棧(棧幀中的本地變量表)中引用的對象
  • 方法區中類靜態引用的對象和常量應用對象
  • 本地方法棧中JNI(即一般說的Native 方法)引用的對象

那麼在開發中常見的內存泄漏常見就可以對應起來:

  1. 單例對象持有 Activity 的 Context 引用 => 方法區內存溢出
  2. 註冊和反註冊。如果沒有反註冊,由於一般註冊用集合保持引用,沒有反註冊 => 堆內存溢出
  3. Bitmap對象,引起的內存泄漏 => 方法區內存溢出
  4. I/O操作,db操作,未關閉 => 直接內存溢出

等等其他一些方式引起的內存泄漏都可以根據以上規則進行匹配判斷

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