Java 內存空間


1. 概述

Java 不像 C/C++ 需要程序員自己管理內存,Java 把內存控制的權利交給類 Java 虛擬機。

2. 運行時數據區域

JVM 在 Java 程序運行時把它所管理的內存劃分爲幾個不同的數據區域。

2.1 程序計數器

程序計數器是一塊較小的內存,它可以看作 ++當前線程++ 所執行的字節碼的行號指示器。在虛擬機的概念模型裏,字節碼解釋器的工作就是通過改變這個 ++計數器的值++ 來選取下一條需要執行的字節碼,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要這個計數器來完成

如上圖所示,程序計數器是線程私有的。

如何執行工作

如果線程正在執行一個 Java 方法,這個計數器記錄的正是執行的虛擬機字節碼指令的地址,如果執行的是 Native 方法,這個計數器值爲空。

2.2 Java 虛擬機棧

Java 虛擬機棧是線程私有的,其生命週期與線程相同。

虛擬機棧描述的是 Java 方法執行的內存模型: 每個 Java 方法執行的同時都會創建一個 棧幀(stack frame) 用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。每一個方法從調用到執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程。

平時的把 Java 內存分爲 堆內存(heap) 和 棧內存(stack) 的分類方法是比較粗糙的,實際分類方法十分複雜。這種分類方法中棧即爲虛擬機棧,或爲虛擬機中的局部變量表。

局部變量表存放了編譯期可知的各種數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(不等同於對象本身,可能是一個對象起始地址的引用指針,也可能是指向一個代表對象的句柄或其他與此對象相關的位置)和returnAddress(指向一條字節碼指令的地址)。

局部變量表所需的內存空間在編譯期間分配完成,當進入一個方法時,這個方法需要在棧幀中分配多的的局部變量空間是完全確定的,在方法的運行期間不會改變局部變量表的大小。

2.3 本地方法棧

本地方方法棧與虛擬機棧發揮的作用相似,不同的是該棧爲 Native 方法服務。

2.4 Java 堆

Java 堆對於大部分應用來說都是 JVM 所管理的內存中最大的一塊。Java 堆是 所有線程共享 的一塊內存區域,在虛擬機啓動時創建。Java 堆的唯一的目的就是存放對象實例,幾乎所有的對象實例都在這裏分配內存 -- 所有的對象實例以及數組都要在堆上分配

Java 堆的分配可以在物理上不連續的內存空間,只要邏輯上連續就可以,可以固定大小,也可以擴展空間。

Java 堆是 GC 發生的主要區域。

2.5 方法區

方法區與 Java 堆一樣是所有線程共享的內存空間,++它用於儲存已被虛擬機加載的類信息、常量、靜態常量、即時編譯器編譯後的代碼等數據++。Java 虛擬機把方法區描述爲堆的一個邏輯部分,但是它還有一個別名 -- Non-Heap(非堆),目的應該是與 Java 堆區分。

2.6 運行時常量池

運行區常量池是方法區的一部分。 Class 文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是 常量池 ,用於存放編譯器生成的各種字面量和符號引用,這部分內容將在類加載後進入方法去的運行時常量池中存放。

字面量和符號引用-->常量池-->運行時常量池

2.7 直接內存

沒有接觸過相關概念。

直接內存(Direct Memory)並不是虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域。但是這部分內存也被頻繁地使用,而且也可能導致OutOfMemoryError異常出現,所以我們放到這裏一起講解。

2.8 小結

數據區域 功能 線程相關 備註
程序計數器 字節碼執行指示器 線程私有
Java 虛擬機棧 爲 Java方法服務、存放編譯期基本數據類型以及對象引用 線程私有 平常被稱爲的 "棧"、空間較小
本地方法棧 與 Java 虛擬機棧類似,爲 Native 方法服務 線程私有
Java 堆 存放對象(對象實例以及數組) 線程共享 GC 主要區域、空間較大
方法區 存儲類信息、常量、靜態變量、即時編譯器編譯後等數據 線程共享
運行時常量池 常量池存放編譯期生成的各種字面量和符號引用、常量池在類加載後存儲在運行時常量池 線程共享 方法區的一部分、常量池會存儲在其中
直接內存

3. 附錄

1. 深入理解Java虛擬機:JVM高級特性與最佳實踐

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