目錄
- 1 關于自動記憶體管理
- 2 運行時資料區域
- 2.1 程式計數器
- 2.2 虛擬機堆疊
- 2.2.1 區域變數表
- 2.2.2 運算元堆疊
- 2.3 本地方法堆疊
- 2.4 堆
- 2.5 方法區
- 2.5.1 運行時常量池
- 3 直接記憶體
- 4 總結
1 關于自動記憶體管理
- Java是由jvm來管理記憶體,包括自動分配以及自動回收,因此它不容易出現記憶體泄漏和記憶體溢位問題,
- C/C++,由程式員手動管理記憶體,手動完成:使用前申請記憶體,使用后釋放記憶體,
2 運行時資料區域
Java虛擬機在執行Java程式的程序中會把它所管理的記憶體劃分為若干個不同的資料區域,這些區域有各自的用途,以及創建和銷毀的時間,
Java虛擬機所管理的記憶體 包括以下幾個運行時資料區域:

2.1 程式計數器
- 程式計數器(Program Counter Register):存盤當前執行緒所執行的位元組碼指令的記憶體地址,位元組碼解釋器作業時就是通過改變這個計數器的值來選取下一條需要執行的位元組碼指令,【通過PC來尋找下一條要執行的指令】,
- 程式計數器是執行緒私有的,cpu通過輪流分配時間片來執行執行緒,為了執行緒切換后能恢復到正確的執行位置,顯然每個執行緒都需要有一個獨立的程式計數器,
- 如果執行緒正在執行的是一個Java方法,PC記錄的是正在執行的位元組碼指令的地址;如果正在執行的是本地(Native)方法,這個計數器值則應為空,【todo 為什么本地方法時為空】
2.2 虛擬機堆疊
- 虛擬機堆疊描述的是Java方法執行的執行緒記憶體模型:每個方法被執行的時候,jvm會同步創建一個堆疊幀[后續章節詳解](Stack Frame)用于存盤區域變數表、運算元堆疊、動態連接、方法出口等資訊,
- 虛擬機堆疊也是執行緒私有的,它的生命周期與執行緒相同,
2.2.1 區域變數表
JDK8之前,對jvm記憶體的認知只停留在:堆記憶體(Heap)和堆疊記憶體(Stack),而“堆疊”通常就是指這里講的虛擬機堆疊,或者更多的情況下只是指虛擬機堆疊中區域變數表部分,
- 區域變數表存盤:基本資料型別(八種:boolean、byte、char、short、int、 float、long、double)、物件參考(可能是一個指向物件起始 地址的參考指標)和returnAddress 型別(指向了一條位元組碼指令的地址),
- 區域變數表所需的記憶體空間在編譯期間完成分配,當進入一個方法時,這個方法需要在堆疊幀中分配多大的區域變數空間是完全確定 的,在方法運行期間不會改變區域變數表的大小,【這里的大小僅值變數槽的數量】
- 區域變數表以區域變數槽(Slot)來存盤資料,其中64位長度的long和 double型別的資料會占用兩個變數槽,其余的資料型別只占用一個,(通常一個槽占據N個位元組,N大小由不同的虛擬機實作決定),
關于堆疊的記憶體資料分析,在后續章節中會有更深入分析,在本節中這里僅引入概念,
2.2.2 運算元堆疊
關于方法呼叫時的進堆疊跟出堆疊的原理,在《深入理解計算機系統》系列筆記的后續章節中會進行總結,
2.3 本地方法堆疊
- 本地方法堆疊(Native Method Stacks)與虛擬機堆疊作用是非常相似的,其區別只是虛擬機堆疊為虛擬機執行Java方法(也就是位元組碼)服務,而本地方法堆疊則是為虛擬機使用到的本地(Native) 方法服務,
- 執行緒私有的,
2.4 堆
- Java堆(Java Heap)存盤物件的實體,
- Java堆是執行緒共享的,且比較大的一塊記憶體區域,在虛擬機啟動時創建,
- Java堆既可以被實作成固定大小的,也可以是可擴展的,不過當前主流的Java虛擬機都是按照可擴展來實作的(通過引數-Xmx和-Xms設定),
- 可彈性伸縮,但不會超過設定的最大容量,如果在Java堆中沒有記憶體完成實體分配,并且堆也無法再 擴展時,Java虛擬機將會拋出OutOfMemoryError例外
- Java堆可以處于物理上不連續的記憶體空間中,但在邏輯上它應該 被視為連續的,
2.5 方法區
- 方法區存盤已被虛擬機加載的class的型別資訊、常量、靜態變數、即時編譯器編譯后的代碼快取等資料,
- 方法區是執行緒共享,
- 方法區不需要連續的記憶體、可以選擇固定大小或者可擴展,甚至還可以選擇不實作垃圾收集(因為這部分記憶體通常不滿足回收條件)
- 方法區無法滿足新的記憶體分配需求時,將拋出 OutOfMemoryError例外,
2.5.1 運行時常量池
- 存放編譯期生成的各種字面量與符號參考
- 運行時常量池(Runtime Constant Pool)是方法區的一部分
3 直接記憶體
- 首先,直接記憶體(Direct Memory)并不是虛擬機運行時資料區的一部分,也不是《Java虛擬機規范》中 定義的記憶體區域
- 它可能導致OutOfMemoryError例外出現,有必要了解,
在JDK 1.4中新加入了NIO(New Input/Output)類,引入了一種基于通道(Channel)與緩沖區 (Buffer)的I/O方式,它可以使用Native函式庫直接分配堆外記憶體,然后通過一個存盤在Java堆里面的 DirectByteBuffer物件作為這塊記憶體的參考進行操作,這樣能在一些場景中顯著提高性能,因為避免了 在Java堆和Native堆中來回復制資料,
顯然,本機直接記憶體的分配不會受到Java堆大小的限制,但是,既然是記憶體,則肯定還是會受到 本機總記憶體(包括物理記憶體、SWAP磁區或者分頁檔案)大小以及處理器尋址空間的限制,一般服務 器管理員配置虛擬機引數時,會根據實際記憶體去設定-Xmx等引數資訊,但經常忽略掉直接記憶體,使得 各個記憶體區域總和大于物理記憶體限制(包括物理的和作業系統級的限制),從而導致動態擴展時出現 OutOfMemoryError例外,
關于記憶體的深入了解,在《深入理解計算機系統》系列筆記的后續章節中會進行總結,
4 總結
Java記憶體區域及其資料類別概覽:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/508915.html
標籤:Java
上一篇:Java代碼中System.currentTimeMillis()方法具有什么功能呢?
下一篇:day39-網路編程01
