Java 深入解析:JVM對象創建與內存機制全景圖

第一章:引言

Java 是一種面向對象的編程語言,對象(Object)是其最基本的組成單位。Java 的“一切皆對象”不僅體現在語法層面,更體現在運行時,幾乎所有數據都以對象形式存在于內存中。

然而,很多開發者對 Java 對象的理解還停留在語言層面,比如 new 關鍵字、類結構、方法調用等,卻對底層 JVM 是如何創建、布局、管理這些對象知之甚少。

在性能調優、內存泄漏分析、高并發系統開發、或處理復雜對象圖結構時,深入理解 Java 對象在 JVM 層面的行為就顯得至關重要。

第二章:JVM 內存結構概覽

要理解 Java 對象在 JVM 中的行為,首先要掌握 JVM 的整體內存結構。Java 虛擬機將運行時數據區劃分為若干區域,每一部分都有特定的職責。

Java 內存區域全解

根據 Java 虛擬機規范,JVM 的主要內存結構如下:

1. 程序計數器(Program Counter Register)

  • 每條線程都有獨立的程序計數器,是線程私有的內存空間。

  • 記錄當前線程所執行的字節碼指令地址。

  • 如果線程正在執行的是一個 native 方法,那么該計數器值為 undefined。

2. 虛擬機棧(JVM Stack)

  • 每個方法被調用時都會創建一個棧幀(Stack Frame)。

  • 包含局部變量表、操作數棧、動態鏈接、返回地址等。

  • 線程私有,隨線程創建而創建,隨線程銷毀而銷毀。

  • 拋出 java.lang.StackOverflowError 通常是由于棧幀過深或死遞歸導致。

3. 本地方法棧(Native Method Stack)

  • 為虛擬機使用到的 native 方法服務。

  • 類似于 JVM 棧,只不過用于本地方法。

  • 并不是所有 JVM 都實現這個棧,HotSpot 把 JVM 棧與本地方法棧合并實現。

4. Java 堆(Heap)

  • 所有對象實例和數組的內存都在這里分配。

  • 是垃圾收集器管理的主要區域,也被稱作 GC 堆。

  • 在 JVM 啟動時創建,整個 JVM 進程中只有一個。

  • 可通過 -Xms-Xmx 設置最小/最大堆大小。

Heap 的分代結構(HotSpot 實現)
  • 新生代(Young Generation)

    • 包括 Eden 和兩個 Survivor 區域(S0 / S1)。

    • 新生對象一般先分配在 Eden 中。

  • 老年代(Old Generation)

    • 存活時間較長的對象會被晉升到老年代。

5. 方法區(Method Area)

  • 存儲已被虛擬機加載的類信息、常量、靜態變量、JIT 編譯后的代碼等。

  • 屬于線程共享區域。

  • Java 8 之前叫做 Permanent Generation(永久代)。

  • Java 8 起使用本地內存中的 Metaspace 替代永久代。

Metaspace 特點:
  • 存儲類元數據(類的結構定義,如字段、方法等)。

  • 分配在本地內存(非堆內存)中,大小受操作系統限制。

  • 參數調整示例:

-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m

6. 運行時常量池(Runtime Constant Pool)

  • 每個類或接口都有自己的常量池表。

  • 包括字面量(如字符串常量)和符號引用(如類、方法、字段的符號引用)。

  • 位于方法區(Java 8 中即 Metaspace)中。

7. 直接內存(Direct Memory)

  • 并非 JVM 運行時數據區的一部分。

  • java.nio 包中的 ByteBuffer.allocateDirect() 直接分配。

  • 屬于操作系統層級的內存,繞過 JVM 堆,減少復制,提高性能。

  • 大量使用會導致 OutOfMemoryError: Direct buffer memory


通過掌握 JVM 的內存結構,我們可以更好地理解 Java 對象為何分配在某個區域,以及這些內存區域對對象生命周期和性能有怎樣的影響。

第三章:Java 對象的創建過程

Java 對象的創建在 JVM 中并不是一句 new 指令那么簡單,它涉及類加載機制、內存分配策略、并發安全控制、對象頭初始化等多個底層細節。

1. 創建流程概覽

  1. 類加載檢查

  2. 分配內存

  3. 初始化零值

  4. 設置對象頭

  5. 執行構造函數

2. 類加載檢查

?Java 類加載機制詳解

當 JVM 執行 new 指令時,首先檢查該類是否已經被加載、解析與初始化。若未加載,會觸發類加載過程,遵循雙親委派機制。

Class<?> clazz = Class.forName("com.example.Person");

只有類加載完成后,JVM 才允許創建其實例。

3. 內存分配

對象實例的內存一般分配在堆上。JVM 中使用以下幾種策略進行分配:

3.1 指針碰撞(Bump-the-pointer)
  • 適用于堆內存連續的情況;

  • 分配時只需移動一個“空閑指針”;

  • 高效但對堆碎片要求高。

3.2 空閑列表(Free List)
  • 適用于堆內存不連續的情況;

  • 使用空閑內存塊列表管理內存;

  • 分配成本高于指針碰撞。

3.3 TLAB(Thread Local Allocation Buffer)
  • Java 8 默認開啟;

  • 為每個線程分配私有緩沖區,避免鎖爭用;

  • 啟動參數:

    -XX:+UseTLAB -XX:+PrintTLAB

4. 默認值初始化

內存分配后,JVM 會將對象字段初始化為默認值:

public class Person {int age;         // 默認 0boolean active;  // 默認 falseString name;     // 默認 null
}

此階段僅進行“零值填充”,尚未執行構造函數邏輯。

5. 設置對象頭

每個 Java 對象都有一個對象頭(Object Header),包含兩部分:

  • Mark Word:存儲哈希碼、GC 年齡、鎖標志位等;

  • 類型指針(Klass Pointer):指向類元數據(即 Class 對象)。

+------------------+--------------------------+
| ? ? Mark Word ? ?| ? Klass Pointer(類指針) |
+------------------+--------------------------+

6. 執行構造函數

最后,JVM 會執行對象對應的構造函數(字節碼中的 <init> 方法),完成字段賦值、邏輯初始化等操作:

Person p = new Person("Alice", 30);

這時對象才真正具備業務語義。


小結

Java 中一句簡單的 new,在 JVM 內部需要經歷:

  • 類是否已加載

  • 采用何種內存分配策略

  • 字段默認值填充

  • 設置對象頭(用于 GC/鎖等)

  • 執行構造邏輯

理解這一過程有助于我們更精準地定位對象創建帶來的性能問題,如頻繁 GC、大量臨時對象分配等。

第四章:Java 對象的內存布局

Java 對象在 JVM 內存中的實際結構是由虛擬機內部定義的,通常包括以下三部分:

  1. 對象頭(Object Header)

  2. 實例數據(Instance Data)

  3. 對齊填充(Padding)

4.1 對象頭(Object Header)

對象頭通常包含兩部分:

  • Mark Word:存儲對象的哈希碼、GC 分代年齡、鎖信息等。

  • Class Pointer:指向對象所屬類的元數據(Klass 指針)。

在 64 位 JVM 中,還可能包括壓縮類指針或對象指針,這取決于是否啟用了如下 VM 參數:

-XX:+UseCompressedOops -XX:+UseCompressedClassPointers

這些壓縮技術能有效降低指針所占空間,從而節省整體內存消耗。

4.2 實例數據(Instance Data)

實例數據部分存儲類中聲明的所有字段值,包括從父類繼承的字段。字段的內存排列順序通常按照以下規則優化:

  • 父類字段排在子類字段之前;

  • 同一類型的字段盡可能排列在一起,以提高緩存效率;

  • boolean 等小字段可能會被重排聚合,減少內存碎片。

4.3 對齊填充(Padding)

JVM 要求對象的總大小是 8 字節的倍數。如果對象頭和實例數據加起來不是 8 的倍數,JVM 會在末尾填充字節來對齊。

這部分填充是內部機制,程序中不可見,但會增加對象內存總開銷。


示例:使用 JOL 查看對象布局

我們可以使用 JOL(Java Object Layout)工具來直觀查看 Java 對象的內存布局。

示例類:
public class Simple {int x;boolean flag;
}
使用 JOL 分析:
import org.openjdk.jol.info.ClassLayout;public class Main {public static void main(String[] args) {Simple simple = new Simple();System.out.println(ClassLayout.parseInstance(simple).toPrintable());}
}
輸出結構示意:
OFFSET  SIZE    TYPE               DESCRIPTION
0       8       (object header)    Mark Word
8       4       int                Simple.x
12      1       boolean            Simple.flag
13      3       (alignment gap)    Padding to 16 bytes

注:最終內存布局取決于 JVM 設置和字段聲明順序。


小結

Java 對象的內存布局對理解 JVM 行為、優化性能、調試問題都至關重要。它直接影響如下方面:

  • GC 掃描與壓縮行為

  • 鎖機制實現(偏向鎖、輕量級鎖等)

  • 對象大小與內存占用估算

  • 字段訪問性能優化

理解對象頭、字段排列與對齊規則,是掌握 JVM 對象模型的關鍵一步。

第五章:對象的訪問定位方式

在 Java 中,對象并非通過裸地址直接訪問,而是依賴 JVM 內部的訪問定位機制。主要有兩種對象定位方式:

  1. 句柄訪問(Handle Access)

  2. 直接指針訪問(Direct Pointer Access)

不同的 JVM 實現可能采用不同的方式。以 HotSpot 為例,默認采用的是直接指針訪問方式。


5.1 句柄訪問方式

在句柄訪問方式中,Java 堆中劃出一塊句柄池(Handle Pool),對象的引用變量實際上指向的是句柄,而不是對象本身。句柄中包含兩個指針:

  • 指向對象實例數據的指針;

  • 指向對象類型元數據的指針。

示例結構:
引用變量↓句柄(Handle)↙         ↘
對象地址    類型元數據地址
優點:
  • 對象在 GC 移動時,只需更新句柄中的指針,引用不變;

  • 實現更加穩定、適用于移動頻繁的對象。

缺點:
  • 每次訪問需兩次指針解引用,性能較低。


5.2 直接指針訪問方式(HotSpot 默認)

在直接指針方式下,對象引用變量直接保存對象在堆中的地址。對象頭中存儲著類型信息。

示例結構:
引用變量↓
對象實例地址(含類型元數據指針)
優點:
  • 訪問速度快,僅一次指針解引用;

  • 結構更緊湊。

缺點:
  • 如果對象在 GC 中被移動,必須更新所有指向它的引用。


5.3 對比總結

訪問方式引用中存儲內容優點缺點
句柄訪問句柄地址對象移動時引用不變,結構穩定每次訪問多一次間接尋址
直接指針訪問對象地址性能高,訪問快對象移動需更新所有引用

5.4 與壓縮指針配合使用

Java 8 引入了指針壓縮(Compressed OOPs)機制,在啟用 64 位 JVM 的同時,允許引用仍使用 32 位地址存儲,從而節省空間。

啟用參數:
-XX:+UseCompressedOops
-XX:+UseCompressedClassPointers

通過這些參數,引用字段仍可僅占用 4 字節空間,提升了對象布局的緊湊性和內存利用率。


5.5 工具驗證:JOL 觀察引用偏移量

結合 JOL 工具可以觀察引用類型字段的內存偏移,間接推斷 JVM 是否啟用了壓縮指針。

public class RefTest {Object ref;
}public class Main {public static void main(String[] args) {System.out.println(ClassLayout.parseInstance(new RefTest()).toPrintable());}
}

若字段 ref 的偏移量為 12(非 16),說明使用了壓縮引用。


小結

對象的訪問定位方式影響著 JVM 的訪問性能、GC 策略和內存使用:

  • HotSpot 采用 直接指針訪問,配合壓縮指針優化性能與空間;

  • 句柄方式 提供更高的內存遷移靈活性,適合對象頻繁移動的環境;

  • 工具如 JOL 能協助我們理解 JVM 內部結構布局。

理解對象的訪問方式是深入掌握 JVM 內部工作機制的重要一環,有助于我們在高性能系統中做出更合理的內存布局與 GC 策略決策。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/88682.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/88682.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/88682.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Redis 基本操作筆記

1. Redis 簡介 Redis&#xff08;Remote Dictionary Server&#xff09;是一個開源的、高性能的鍵值對存儲系統&#xff0c;通常作為數據庫、緩存、消息中間件等使用。它支持多種數據類型&#xff0c;包括字符串、哈希、列表、集合、有序集合等。 Redis 特點&#xff1a; 性能&…

Docker從環境配置到應用上云的極簡路徑

Docker從環境配置到應用上云的極簡路徑主要包括環境配置、應用容器化、選擇云平臺及部署應用等步驟&#xff0c;具體如下&#xff1a; - 配置Docker環境&#xff1a; - 安裝Docker&#xff1a;根據操作系統下載對應版本的Docker安裝包。如在Linux系統中&#xff0c;可使用命令…

Slicer渲染Dicom到nrrd

Slicer渲染Dicom到nrrd 工作中遇到一些處理Dicom數據的需求&#xff0c;個人通過網絡上的一些教程 對于原始數據嘗試轉換到nrrd時&#xff0c;發現部分的窗體數據的渲染方向不一致 進一步發現這些很多定義的方向是跟設備廠家強相關的&#xff0c;不同廠家對于同一段的Dicom參…

QT中設計qss字體樣式但是沒有用【已解決】

檢查一下stylesheet里面是不是有不能被QT讀取的CSS語言&#xff0c;可能會跟字體顏色沖突錯誤示范&#xff1a;/* 錯誤示例&#xff1a;QSS 中使用 box-shadow */ QPushButton {box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); /* Qt 不支持此屬性 */ }刪掉就行了如果后續想用陰影…

uniapp獲取狀態欄高度,膠囊按鈕的高度,底部安全區域的高度,自定義導航欄

相關API uni.getSystemInfoSync() uni.getMenuButtonBoundingClientRect() 創建一個utils文件夾&#xff0c;該文件下封裝一個systemInfo.js /*** 系統信息工具類* 封裝獲取系統狀態欄、導航欄和安全區域等相關信息的方法*/// 獲取系統信息并緩存 const systemInfo uni.get…

jQuery 文本屬性值

一、前言在網頁開發中&#xff0c;我們經常需要對頁面上的文本內容進行操作&#xff0c;例如動態修改段落文字、讀取用戶輸入框的內容、更新按鈕文本等。jQuery 提供了簡潔而強大的方法來處理這些常見的文本操作需求。本文將帶你全面了解 jQuery 中用于操作文本內容的三個核心方…

JAVA并發——為什么Java中的ThreadLocal對key的引用為弱引用

1、ThreadLocal 的用途 給每個線程提供自己獨立的變量副本&#xff0c;實現線程間隔離。 常用于&#xff1a; 數據庫連接、Session 緩存、用戶上下文&#xff08;如 userId&#xff09;線程池中的線程復用時避免共享污染&#xff1b;實現線程封閉的設計模式 2、內存泄漏 使用弱…

【C++】多線程同步三劍客介紹

目錄 條件變量 頭文件 主要操作函數 1、等待操作 2、喚醒操作 使用示例 信號量 頭文件 主要操作函數 1、信號量初始化 2、等待操作&#xff08;P操作&#xff09; 3、信號操作&#xff08;V操作&#xff09; 4、獲取信號量值 5、銷毀信號量 使用示例 互斥鎖 …

《Java Web程序設計》實驗報告八 JSP+Servlet+JDBC+MySQL實現課程管理

目 錄 一、實驗目的 二、實驗環境 三、實驗步驟和內容 1、小組成員分工&#xff08;共計4人&#xff09; 2、實驗方案 3、實驗結果與分析 4、項目任務評價 四、遇到的問題和解決方法 五、實驗總結 一、實驗目的 1、掌握mysql的安裝、數據庫表單創建 2、掌握JDBC的鏈接…

基于數據挖掘的課程推薦系統研究

摘要本研究設計并開發了一套基于先進數據挖掘技術的智能化課程推薦系統。該系統創新性地采用了協同過濾算法與內容推薦算法相結合的混合推薦策略&#xff0c;通過深度分析學生在學習平臺上的歷史行為數據&#xff08;包括選課記錄、學習時長、測試成績等&#xff09;以及課程的…

【SCI 4區推薦】《Journal of Visual Communication and Image Representation》

期刊簡介&#xff1a;《視覺傳達與圖像表示雜志》&#xff08;Journal of Visual Communication and Image Representation&#xff09;致力于發表視覺傳達與圖像表示領域的最前沿研究&#xff0c;特別強調多學科交叉領域中的新技術和理論應用。這本期刊涵蓋的研究范圍廣泛&…

20250711_Sudo 靶機復盤

target:192.168.43.20 外部打點 &#xff08;文件上傳&#xff09; nmap掃一下&#xff0c;80,22 開放 掃目錄&#xff0c;發現 README.md [17:04:30] 200 - 664B - /Dockerfile [17:04:38] 200 - 34KB - /LICENSE …

STEP 7-Micro/WIN SMART 編程軟件:從入門到精通的使用指南

STEP 7-Micro/WIN SMART 編程軟件&#xff1a;從入門到精通的使用指南 在工業自動化控制領域&#xff0c;編程軟件是連接工程師與 PLC 的橋梁&#xff0c;而 STEP 7-Micro/WIN SMART 作為 S7-200 SMART PLC 的專用編程工具&#xff0c;以其友好的界面和高效的編程能力備受青睞。…

模型訓練與部署注意事項篇---resize

圖像大小的影響在 YOLOv 系列模型的訓練和推理部署過程中&#xff0c;圖像大小的選擇是影響模型性能&#xff08;精度、速度、泛化能力&#xff09;的關鍵因素之一。兩者的關系既相互關聯&#xff0c;又存在一定的靈活性&#xff0c;具體可從以下幾個方面詳細分析&#xff1a;一…

【Python】venv:配置獨立鏡像源

為某個特定的 venv 虛擬環境設置 pip 鏡像源&#xff0c;使得該環境下的 pip 安裝始終使用自定義鏡像源&#xff0c;不影響系統 pip&#xff0c;也不依賴用戶級配置文件。環境準備 1. 創建虛擬環境 python -m venv venv2. 激活虛擬環境Windows: .\venv\Scripts\activateLinux/m…

日本語言學校:簽證制度類 Prompt 的結構整理路徑與策略

日本語言學校&#xff1a;簽證制度類 Prompt 的結構整理路徑與策略 我們在構建語言留學語義系統的過程中&#xff0c;嘗試以“簽證風險”為例&#xff0c;探索如何讓結構信息被更好地保留下來。本文不介紹 Prompt 本身&#xff0c;也不夸大其作用&#xff0c;而是希望借此與更…

RFCOMM協議詳解:串口仿真與TCP/IP協議棧移植技術——面試高頻考點與真題解析

一、RFCOMM 協議核心考點與高頻面試問題1.1 協議基礎與核心功能考點解析&#xff1a;RFCOMM&#xff08;Radio Frequency Communication&#xff09;是藍牙協議棧中實現串口仿真的核心協議&#xff0c;基于 L2CAP 協議提供類似 RS-232 的可靠數據流傳輸。其核心功能包括&#x…

【編程實踐】利用open3d生成物體的最長邊方向并可視化

1 利用3d軟件生成一個長方體 邊長隨意&#xff0c;長度隨意 2 導出為模型文件并采樣為點云數據 從mesh表面進行采樣&#xff0c;點數根據自己需求進行設置&#xff0c;此處設置為100000。采樣結果&#xff1a;3 識別OBB外接框并可視化長邊方向import numpy as np import open3d…

1. 好的設計原則

目錄一、應該具備的性質二、面向對象設計原則三、詳解3.1 開閉原則3.2 單一職責原則3.3 里氏替換原則3.4 依賴倒置原則3.5 接口隔離原則3.6 合成復用原則3.7 迪米特原則一、應該具備的性質 可擴展性靈活性可插入性 二、面向對象設計原則 以下設計原則的重要性從高到低排列 …

深度學習圖像分類數據集—貓七種表情識別分類

該數據集為圖像分類數據集&#xff0c;適用于ResNet、VGG等卷積神經網絡&#xff0c;SENet、CBAM等注意力機制相關算法&#xff0c;Vision Transformer等Transformer相關算法。 數據集信息介紹&#xff1a;貓七種表情識別分類&#xff1a;[Angry, Disgusted, Happy, Normal, Sa…