日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

【Android 内存优化】Java 内存模型 ( Java 虚拟机内存模型 | 线程私有区 | 共享数据区 | 内存回收算法 | 引用计数 | 可达性分析 )

發布時間:2025/6/17 Android 40 豆豆

文章目錄

  • 一、 Java 虛擬機內存模型
  • 二、 程序計數器 ( 線程私有區 )
  • 三、 虛擬機棧 ( 線程私有區 )
  • 四、 本地方法棧 ( 線程私有區 )
  • 五、 方法區 ( 共享數據區 )
    • 1. 方法區
    • 2. 運行時常量池
  • 六、 堆區 ( 共享數據區 )
  • 七、 內存溢出類型
  • 八、 引用計數算法回收內存
  • 九、 可達性分析算法回收內存





一、 Java 虛擬機內存模型



Java 內存優化 , 首當其沖就是處理 Java 內存泄漏問題 , 這是 Java 程序最主要的內存問題 , 大量的內存泄漏會導致內存溢出 ;



Java 虛擬機內存機制 : Java 虛擬機中內存分為兩部分 , 線程私有部分 , 共享數據區 ;


① 共享數據區 : 方法區 ( Method Area ) , 堆區 ( Heap Area ) ; 其中方法區中包含常量池 ;

② 線程私有數據區 : 程序計數器 ( PC ) , 虛擬機棧 ( VM Stack ) , 本地方法棧 ( Native Method Stack ) ;


這是 Java 虛擬機規范定義的內存分區 , 但是具體的廠家實現可能不完全一致 , 如 Sun JDK , Open JDK 等 ;

Android 中的 Java 虛擬機 跟上述 Java 規范有很大不同 ;





二、 程序計數器 ( 線程私有區 )



程序計數器 :


① 作用 : 該內存空間很小 , 主要用于指示執行的代碼行 , 程序計數器指向的代碼行 , 就是下一行將要執行的代碼 ;

② 線程切換運行 : Java 多線程是搶占式執行的 , 經常出現線程 AAA 執行時 , 切換到線程 BBB , 如果線程 BBB 執行完畢回到線程 AAA , 這里就需要記住線程 AAA 之前執行到哪了 , 這就需要用到線程私有的數據區的程序計數器 ( PC ) ;

③ 執行 Java 代碼 : 線程執行 Java 代碼時 , 程序計數器記錄的是虛擬機字節碼地址 ;

④ 執行 Native C/C++ 代碼 : 線程執行 native 代碼時 , 程序計數器記錄的 值是空值 null ;


程序計數器 區域沒有定義 內存溢出 異常 , 這個區域很小 ;





三、 虛擬機棧 ( 線程私有區 )



1. 虛擬機棧 ( VM Stack ) : 其生命周期與線程相同 , 描述的是 Java 方法執行的內存模型 , 該區域就是棧區 , 與堆區相對應 ;


2. 虛擬機棧中保存的數據 :

  • 局部變量表
  • 操作棧
  • 方法返回地址
  • 動態鏈接
  • 額外附加信息




四、 本地方法棧 ( 線程私有區 )



本地方法棧 ( Native Method Stack ) : 這是 Native 層 C/C++ 提供的棧內存空間 , 該內存的類型與虛擬機棧內存類型一樣 , 只是語言不同 , 一個 Java 方法的額棧 , 一個是 C/C++ 方法的棧 ;


Hotspot VM 虛擬機中 , 虛擬機棧 與 本地方法棧是一塊內存 , 二者合二為一 ;





五、 方法區 ( 共享數據區 )





1. 方法區


方法區 : 存儲以下內容 ;

  • 類信息 , 如 ClassLoader 加載的 Class
  • 常量 , 存放在運行時常量池中 , 該常量池也是方法區的一部分 ;
  • 靜態變量 , static 變量
  • 即時編譯器( JIT compiler ) 編譯后的代碼

不同的虛擬機 , 實現不同 ;

該區域一般不進行 GC 垃圾回收 ;




2. 運行時常量池


運行時常量池 :

  • 編譯中的 Java 常量 ( public static final )
  • 字符串常量 ( String )
  • final 修飾的常量 ;
  • 符號引用 , 如 類或接口完整名稱 ( 帶包名 ) , 字段名 , 方法名 , 描述符 ;




六、 堆區 ( 共享數據區 )



Java 堆區 :


① 最大區域 : 該內存區是 Java 虛擬機管理的內存中最大的部分 , 是垃圾回收算法 GC 的主要操作區域 ;

② 內存溢出 : OOM ( OutOfMemory ) 內存溢出就是該區域內存被全部占用 , 無法為新的內存申請更多空間 ;





七、 內存溢出類型



內存溢出 :


① 棧內存溢出 : 在 Java 的棧區內存溢出 , 就是 StackOverflowException 棧溢出異常 , 在遞歸的時候 , 如果沒有控制好 , 就會報該異常 ;

② 堆內存溢出 : 在 Java 堆內存中的溢出 , 就是 OutOfMemoryError 堆內存溢出 , 在加載大量數據到內存時 , 會出現該異常 ;





八、 引用計數算法回收內存



引用計數是早期的 GC 回收 Java 對象機制 , 有一定弊端 ;


1. 引用計數簡介 : 使用對象的引用計數 , 確定 Java 對象是否存活 , 確定是否應該被回收 ;


2. 引用計數垃圾回收算法示例說明 :


① 創建對象 : 創建一個 OOO 類型對象 ooo , 此時引用計數為 0 , 如果不將其賦值給一個變量 , 那么很快就會被回收 ;

② 變量 AAA 賦值 : 創建一個 OOO 類型對象 ooo , 將對象 ooo賦值 給變量 AAA , 此時該對象 AAA 引用計數為 111 ;

③ 變量 BBB 賦值 : 創建一個 OOO 類型對象 ooo , 將對象 ooo賦值 給變量 BBB , 此時該對象 BBB 引用計數為 111 ;

BBB 引用 AAA : 變量 BBB 中有 OOO 類型成員變量 , 將 AAA 賦值 給該成員變量 , 此時對象 BBB 引用計數變成 222 ;

AAA 引用 BBB : 變量 AAA 中有 OOO 類型成員變量 , 將 BBB 賦值 給該成員變量 , 此時對象 AAA 引用計數變成 222 ;


此時即使把 A,BA , BA,B 兩個變量都設置成 null , 每個變量的引用計數都減一 , 也無法將引用計數減為 000 , 該對象永遠無法回收 ;


引用計數弊端 : 如果兩個變量之間互相引用 , 引用計數永遠不能變為 000 ;





九、 可達性分析算法回收內存



1. 可達性分析算法 : 以 GC Root 為分析的起點 , 查找對象的引用 , 如果找到一個對象 , 無法被 GC Root 直接或間接引用到 , 那么該對象就可以被回收了 ;


2. GC Root 對象 : GC Root 是一個對象 , 可以是如下對象 ;

  • 虛擬機棧正在運行的引用
  • 靜態屬性
  • 常量
  • JNI 中的對象

GC Root 就是不會被回收的那些的變量 , Android 中就是 Application , 單例類 , 運行中的 Activity 等 ;


3. 第一次掃描回調 finalize 方法 : 對象經過可達性分析后 , 發現沒有引用鏈可以達到 GC Root , 此時就會調用該對象的 finalize() 方法進行標記 , 開發者可以實現該方法 , 進行一些邏輯處理 :

  • ① 釋放資源 : 可以執行一些資源釋放方法 , 一面出現內存泄漏 ;
  • ② 引用自救 : 將對象賦值給指定變量 , 這樣可以避免被 GC 回收內存 ;

4. 可達性分析中對對象的兩次掃描 : 可達性分析時 , 需要對指定對象標記兩次 , 第一次被標記時會調用該對象 finalize() 方法 , 相當于判了死緩 , 此時可以通過添加引用的方式自救 , 如果沒有進行任何干預 , 第 222 次掃描到該對象還沒有到 GCRoot 的引用鏈 , 此時不會調用 finalize() 方法 , 直接就被回收了 ;

總結

以上是生活随笔為你收集整理的【Android 内存优化】Java 内存模型 ( Java 虚拟机内存模型 | 线程私有区 | 共享数据区 | 内存回收算法 | 引用计数 | 可达性分析 )的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。