JVM對象創建全流程解析

一、JVM對象創建流程

在這里插入圖片描述

Ⅰ、類加載檢查——JVM創建對象時先檢查類是否加載

在虛擬機遇到new指令時,比如new關鍵字、對象克隆、對象序列化時,如下字節碼

0: new           #2                  // class com/example/demo/Calculate

檢查指令的參數(#2)是否能在常量池中定位到一個類的符號引用

常量池:
Constant pool:#1 = Methodref          #7.#27         // java/lang/Object."<init>":()V#2 = Class              #28            // my/Calculate#3 = Methodref          #2.#27         // my/Calculate."<init>":()V#4 = Fieldref           #29.#30        // java/lang/System.out:Ljava/io/PrintStream;#5 = Methodref          #2.#31         // my/Calculate.compute:()I#6 = Methodref          #32.#33        // java/io/PrintStream.println:(I)V#7 = Class              #34            // java/lang/Object#8 = Utf8               <init>#9 = Utf8               ()V#10 = Utf8               Code#11 = Utf8               LineNumberTable#12 = Utf8               LocalVariableTable#13 = Utf8               this#14 = Utf8               Lmy/Calculate;#15 = Utf8               compute#16 = Utf8               ()I#17 = Utf8               a#18 = Utf8               I#19 = Utf8               b#20 = Utf8               main#21 = Utf8               ([Ljava/lang/String;)V#22 = Utf8               args#23 = Utf8               [Ljava/lang/String;#24 = Utf8               calculate#25 = Utf8               SourceFile#26 = Utf8               Calculate.java#27 = NameAndType        #8:#9          // "<init>":()V#28 = Utf8               my/Calculate#29 = Class              #35            // java/lang/System#30 = NameAndType        #36:#37        // out:Ljava/io/PrintStream;#31 = NameAndType        #15:#16        // compute:()I#32 = Class              #38            // java/io/PrintStream#33 = NameAndType        #39:#40        // println:(I)V#34 = Utf8               java/lang/Object#35 = Utf8               java/lang/System#36 = Utf8               out#37 = Utf8               Ljava/io/PrintStream;#38 = Utf8               java/io/PrintStream#39 = Utf8               println#40 = Utf8               (I)V

檢查符號引用代表的類是否已經被加載、校驗、準備、解析和初始化,如果沒有加載,通過類加載機制加載類。

Ⅱ、分配內存——創建對象的一大工作就是分配內存

由于類一旦被加載,就可知該類對象所占內存空間(因為對象頭大小、屬性-每個類型占用多少字節是固定的)

為對象分配內存,就是從堆或者棧(一般是堆)中為分配一塊確定大小的空間

劃分內存的方式——通過指針碰撞或者空閑列表的方式分配內存空間:

  • 指針碰撞:默認使用的方式,通過一個指針標識當前已經使用到位置,指針一側是已分配的空間、另一次是未使用的空閑內存,通過指針移動對象所需空間大小來分配內存。要求java堆內存絕對規整,已用空間分配在一側。
  • 空閑列表:通過維護一張空閑列表維護空閑空間的初始位置和塊大小,通過在空閑列表尋找可用的內存塊(對象所需空間>空閑塊時,該空閑塊不可用),分配并更新空閑列表。

并發分配問題——在分配內存的時必然存在多個線程為對象在堆中分配空間(堆是線程共享的區域),就是存在并發分配內存的問題,解決方法:

  • CAS鎖+失敗重試:CAS-Compare And Swap

  • TLAB:本地線程分配緩存-Thread Local Allocate Buffer,先為每個線程在java堆中分配一塊空間,當為該線程的對象分配內存時,先從預分配內存中進行分配(打破了線程競爭同一塊堆空間的問題)

    -XX:+UseTLAB(默認開啟)、-XX:TLABSize設定預分配內存空間大小

Ⅲ、初始化——為分配給對象的內存空間賦0值,不包括對象頭

如果是TLAB(本地線程分配緩存)的分配方式,則初始化提前到為每個線程在java堆中分配一塊空間時進行。

這一過程使java的實例變量和類變量可以在不賦初始值就可使用,只是訪問出的是該類型的0值。

  • 對于基本數據類型(如 intdoublechar 等),如果沒有顯式初始化,它們的默認值如下:

    • int 類型的變量默認值為 0

    • double 類型的變量默認值為 0.0

    • char 類型的變量默認值為 '\u0000'(即空字符)。

    • public class Person {int age; // 沒有初始化,默認為0String name; // 沒有初始化,默認為null
      }
      Person person = new Person();
      System.out.println(person.age); // 輸出 0
      System.out.println(person.name); // 輸出 null
      
  • 對于對象引用類型(如類、接口、數組等),如果沒有顯式初始化,它們的默認值是 null

  • 局部變量:在Java中,局部變量(在方法內部聲明的變量)如果不初始化就直接使用,編譯器會報錯,因為局部變量在使用前必須顯式初始化。

public void test() {int x; // 編譯錯誤:局部變量x可能尚未初始化System.out.println(x);
}

Ⅳ、設置對象頭

對象

  • 對象頭
    • 標記字段(Mark Word):占用內存視操作系統,32位的占4字節(32bit),64位的占8字節(64bit),包括鎖標志位、對象的hashcode、分代年齡、偏向線程ID、偏向鎖時間戳(Epoch)、鎖指針。鎖標志位內容不同則保存的對象信息不同。
    • 類型指針(Klass Pointer):占用內存視是否開啟指針壓縮,開啟指針壓縮占用4字節,不開啟占用8字節,默認開啟。是指向元空間中類的元數據信息的指針,JVM通過這個指針判斷該對象是哪個類的實例。
    • 數組長度(如果對象是數組類型):如果對象是數據類型,存儲數組長度,占用4字節。
  • 實例數據
  • 對齊填充

以下表格是32位的操作系統下默認開啟指針壓縮的對象頭:

標記字段的結構 類型指針
25bit4bit1bit2bit4字節
23bit2bit是否偏向鎖鎖標志位
對象的哈希碼分代年齡001(無鎖)
線程ID:持有偏向鎖的線程ID,標識哪個線程偏向該對象Epoch:偏向鎖的時間戳,用于批量撤銷偏向鎖分代年齡101(無鎖)
指向棧中鎖記錄的指針00(輕量級鎖)
指向重量級鎖指針(操作系統級互斥鎖)10(重量級鎖)
11(GC標記,表示對象待回收,由GC算法確定)

Ⅴ、執行方法

執行方法,按照程序員的意愿進行初始化,為屬性賦值(賦程序員給的值)和執行構造方法。

二、查看對象大小和指針壓縮

1、查看對象的內存布局

引入依賴

        <dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.17</version></dependency>

示例代碼

package com.example.demo;import org.openjdk.jol.info.ClassLayout;/*** 計算對象大小*/
public class JOLSample {public static void main(String[] args) {ClassLayout layout2 = ClassLayout.parseInstance(new A());System.out.println(layout2.toPrintable());}// ‐XX:+UseCompressedOops 默認開啟的壓縮所有指針// ‐XX:+UseCompressedClassPointers 默認開啟的壓縮對象頭里的類型指針Klass Pointer// Oops : Ordinary Object Pointerspublic static class A {//8B mark word//4B Klass Pointer 如果關閉壓縮‐XX:‐UseCompressedClassPointers或‐XX:‐UseCompressedOops,則占用8Bint id; //4BString name; //4B 如果關閉壓縮‐XX:‐UseCompressedOops,則占用8Bbyte b; //1BObject o; //4B 如果關閉壓縮‐XX:‐UseCompressedOops,則占用8B}
}

在64位操作系統上的執行結果(默認開啟指針壓縮):

在這里插入圖片描述

關閉指針壓縮后,引用類型占用的空間變成8字節:

在這里插入圖片描述

根據提供的 JOL(Java Object Layout)輸出,以下是 com.example.demo.JOLSample$A 對象的內存布局分析:

  1. 對象頭(Object Header)

    • Mark Word(標記字):
      • 偏移量:0,大小:8 字節
      • 值:0x0000000000000005
      • 含義:表示對象處于 可偏向狀態biasable),分代年齡為 0age: 0),存儲鎖、GC 狀態等信息。
    • Klass Word(類指針):
      • 偏移量:8,大小:4 字節
      • 值:0xf800cf18
      • 含義:指向類元數據的指針(JVM 開啟指針壓縮后為 4 字節)。
  2. 實例字段(Instance Fields)

    • int id
      • 偏移量:12,大小:4 字節
      • 值:0(默認初始值)。
    • byte b
      • 偏移量:16,大小:1 字節
      • 值:0(默認初始值)。
    • 對齊填充(Padding Gap)
      • 偏移量:17,大小:3 字節
      • 原因:下一個字段 String name 需對齊到 4 字節邊界(20 是 4 的倍數),因此在 byte b 后填充 3 字節。
    • String name
      • 偏移量:20,大小:4 字節
      • 值:null(引用類型,指針壓縮后占 4 字節)。
    • Object o
      • 偏移量:24,大小:4 字節
      • 值:null(引用類型)。
  3. 對象對齊填充(Object Alignment Gap)

    • 偏移量:28,大小:4 字節
    • 原因:對象總大小需對齊至 8 字節(64 位 JVM 的默認對齊)。當前已用 28 字節(0~27),需填充至 32 字節(28 + 4 = 32)。

關鍵指標

  • 實例總大小(Instance Size)32 字節。
  • 空間損失(Space Losses)
    • 內部(Internal)3 字節(字段間填充)。
    • 外部(External)4 字節(對象末尾填充)。
    • 總計損失7 字節。

內存布局圖示

偏移量大小(字節)內容說明
08Mark Word鎖、GC 狀態等
84Klass Word類元數據指針
124int id整型字段
161byte b字節字段
173對齊填充補齊至 4 字節邊界
204String name字符串引用(null
244Object o對象引用(null
284對象對齊填充補齊至 8 字節邊界

總結

  • 對象頭占 12 字節8 + 4),字段數據占 13 字節4 + 1 + 4 + 4),但實際占用 20 字節(含內部填充)。
  • JVM 通過填充確保字段對齊和對象對齊,提高內存訪問效率。
  • 優化建議:若需減少空間,可調整字段順序(如將 byte b 放在末尾),但 JVM 會自動重排,通常無需手動干預。
2、指針壓縮的JVM配置參數

‐XX:+UseCompressedOops :開啟的壓縮所有指針,默認開啟

‐XX:+UseCompressedClassPointers :開啟的壓縮對象頭里的類型指針Klass Pointer,默認開啟

3、為什么要有指針壓縮

1、在64位的平臺中節約空間和帶寬:在主內存和緩存之間復制較大指針會占用更多帶寬;

2、32位地址最大支持4G內存,通過對對象指針的壓縮編碼、解碼以支持更大的內存配置(不超過32G);

3、堆內存小于4G時不需要開啟指針壓縮,JVM會自動去除高32位地址,使用低虛擬地址空間;

4、堆內存大于32G時,壓縮指針失效,強制使用64位對java對象尋址。(所以堆內存不建議大于32G)

ressedOops :開啟的壓縮所有指針,默認開啟

‐XX:+UseCompressedClassPointers :開啟的壓縮對象頭里的類型指針Klass Pointer,默認開啟

3、為什么要有指針壓縮

1、在64位的平臺中節約空間和帶寬:在主內存和緩存之間復制較大指針會占用更多帶寬;

2、32位地址最大支持4G內存,通過對對象指針的壓縮編碼、解碼以支持更大的內存配置(不超過32G);

3、堆內存小于4G時不需要開啟指針壓縮,JVM會自動去除高32位地址,使用低虛擬地址空間;

4、堆內存大于32G時,壓縮指針失效,強制使用64位對java對象尋址。(所以堆內存不建議大于32G)

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

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

相關文章

深度學習從入門到精通:PyTorch實戰與核心原理詳解

掌握深度學習核心概念&#xff0c;玩轉PyTorch框架&#xff0c;從理論到實戰一站式學習指南 &#x1f680; 一、深度學習全景圖 &#x1f31f; 人工智能金字塔 &#x1f50d; 深度學習核心優勢 ??優勢????劣勢????適用場景??自動特征提取依賴大數據圖像識別&…

計算機網絡期末 物理層

目錄 數據通信基礎(理解) 傳輸介質(熟悉) 基帶傳輸(熟悉) 數字編碼(熟悉) 頻帶傳輸與調制解調(理解) 多路復用技術(了解) 物理層設備與極限速率(掌握) 數據通信基礎(理解) 一堆概念 通信的類型 同步技術 傳輸介質(熟悉) 有線介質 同軸電纜 雙絞線 光纖 無線介質 無線電…

力扣-139.單詞拆分

題目描述 給你一個字符串 s 和一個字符串列表 wordDict 作為字典。如果可以利用字典中出現的一個或多個單詞拼接出 s 則返回 true。 注意&#xff1a;不要求字典中出現的單詞全部都使用&#xff0c;并且字典中的單詞可以重復使用。 class Solution {public boolean wordBrea…

LeetCode-1679. K 和數對的最大數目

給你一個整數數組 nums 和一個整數 k 。 每一步操作中&#xff0c;你需要從數組中選出和為 k 的兩個整數&#xff0c;并將它們移出數組。 返回你可以對數組執行的最大操作數。 地址&#xff1a;https://leetcode.cn/problems/max-number-of-k-sum-pairs/description/?envTyp…

相機camera開發之差異對比核查四:測試機和對比機的Camera動態參數差異對比及關鍵字

【關注我,后續持續新增專題博文,謝謝!!!】 上一篇我們講了: 這一篇我們開始講: 目錄 一、背景 二、:Camera動態參數差異 2.1:動態參數差異核查項 2.2 :動態參數差異核查關鍵字 2.3 :前置普通拍照動態參數 2.4 :后置普通拍照動態參數 2.5 :后置人像模式…

ModbusTCP轉Profibus網關在配料系統中的配置實踐

在現代飼料企業的生產過程中&#xff0c;自動化技術的應用日益廣泛。其中&#xff0c;ModbusTCP和Profibus是兩種常見的工業通信協議&#xff0c;它們在數據采集和設備控制方面發揮著重要作用。然而&#xff0c;由于這兩種協議在技術上的差異&#xff0c;直接互通往往存在困難。…

雙饋風機分段控制策略的一次調頻模型深度解析

雙饋風機分段控制策略的一次調頻模型深度解析 摘要 隨著風電滲透率的急劇攀升,電力系統慣性降低與一次調頻能力弱化問題日益凸顯。雙饋感應發電機(DFIG)憑借其優越的性能已成為主流機型,但其常規控制策略使其自然不具備響應系統頻率變化的能力。本文深入探討基于分段控制策…

JMeter 高階玩法:分布式壓測的技術核心技術要點

在2025年的數字化浪潮中&#xff0c;網站和應用的性能直接決定用戶體驗和業務成敗&#xff01;想象一下&#xff0c;雙十一促銷期間&#xff0c;你的電商平臺因無法承受高并發而崩潰&#xff0c;或者金融系統在高峰期響應遲緩——這不僅是技術問題&#xff0c;更是商業災難&…

在 Windows 和 Linux 下使用 C/C++ 連接 MySQL 的詳細指南

前言 MySQL 是一種流行的關系型數據庫管理系統&#xff0c;廣泛應用于各種應用程序中。C/C 作為高性能編程語言&#xff0c;常被用于需要與數據庫交互的開發中。下面詳細講解如何在 Windows 和 Linux 平臺下使用 C/C 連接 MySQL 數據庫&#xff0c;幫助你快速上手。 準備工作 …

【人工智能基礎】初識神經網絡

初識神經網絡 本章通過戰勝人類圍棋世界冠軍的AlphaGo案例,介紹神經網絡的基本概念,并闡明其與人工智能、機器學習的關系。 1. AlphaGo與圍棋:神經網絡的實力展示 傳統圍棋程序:基于固定規則 早期的計算機程序依賴人類專家預先設定的策略(“如果A情況發生,則執行B步驟”…

ffmpeg webm 透明通道視頻轉成rgba圖片

import subprocess def webm_to_bgrapng(webm_video_path,bgra_dir):command [ffmpeg,-vcodec, libvpx-vp9, # 指定輸入視頻編碼為 VP9-i, webm_video_path, # 輸入視頻路徑-pix_fmt, "rgba", # 輸出 RGBA 格式&#xff08;保留 Alpha 通道&#xff09;bgra_dir …

SQLite 數據庫操作完整指南

SQLite 數據庫操作完整指南 全面的 SQLite 數據庫操作手冊&#xff0c;涵蓋從基礎操作到高級優化的所有內容 目錄 ** SQLite 簡介與特點 創建和連接數據庫 創建表 數據類型和約束 插入數據 查詢數據 更新數據 刪除數據 多表查詢 視圖 索引優化 觸發器 事務處理 全文搜索 JSO…

Python Luigi 【工作流管理庫】簡介

想全面了解DeepSeek的看過來 【包郵】DeepSeek全攻略 人人需要的AI通識課 零基礎掌握DeepSeek的實用操作手冊指南【限量作者親筆簽名版售完即止】 玩轉DeepSeek這本就夠了 【自營包郵】DeepSeek實戰指南 deepseek從入門到精通實用操作指南現代科技科普讀物AI普及知識讀物人工智…

微服務中分布式事務:Saga模式、TCC模式與消息隊列

Saga模式 Saga模式是一種基于補償的事務管理機制&#xff0c;它將一個長事務分解為多個本地事務&#xff0c;每個本地事務都有一個對應的補償事務。當某個本地事務執行失敗時&#xff0c;Saga模式會依次調用前面已成功執行的本地事務的補償事務&#xff0c;以實現事務的回滾。…

唯美復古風景人像攝影Lr調色教程,手機濾鏡PS+Lightroom預設下載!

調色教程 “唯美復古風景人像攝影 Lr 調色”&#xff0c;是將人物置于如畫的風景之中進行拍攝&#xff0c;再運用 Lightroom&#xff08;Lr&#xff09;軟件&#xff0c;通過專業的調色操作&#xff0c;為照片賦予復古的藝術氣息&#xff0c;讓畫面兼具唯美的視覺享受與懷舊的情…

華為云Flexus+DeepSeek征文|體驗華為云ModelArts快速搭建Dify-LLM應用開發平臺并創建b站視頻總結大模型

華為云FlexusDeepSeek征文&#xff5c;體驗華為云ModelArts快速搭建Dify-LLM應用開發平臺并創建b站視頻總結大模型 什么是華為云ModelArts 華為云ModelArts ModelArts是華為云提供的全流程AI開發平臺&#xff0c;覆蓋從數據準備到模型部署的全生命周期管理&#xff0c;幫助企…

線程池異步處理

List<CompletableFuture<Void>> futures new ArrayList<>();// 提交10個異步任務 for (int i 0; i < 10; i) {CompletableFuture<Void> future CompletableFuture.runAsync(() -> {insertData(batchData); // 每個任務插入一批數據}, pool).t…

STM32HAL庫 -- 8.串口UART通信并開啟printf功能

目錄 1.簡介 2.串口和UART 2.1串口的簡介 2.2UART的簡介 2.3UART通信協議 2.3.1波特率 2.3.2空閑位 2.3.3起始位 2.3.4數據位 2.3.5校驗位 2.3.6停止位 3.STM32的UART 4.HAL庫中常用的操作UART的函數 4.1UART初始化函數 -- HAL_UART_Init 4.2硬件初始化回調函數…

【PyTorch項目實戰】CycleGAN:無需成對訓練樣本,支持跨領域圖像風格遷移

文章目錄 一、風格遷移模型&#x1f3a8;1、發展時間線2、分類與優缺點3、選擇建議4、HuggingFace Demo&#xff08;instruct-pix2pix&#xff09; —— 在線測試 二、論文簡讀&#xff08;1&#xff09;FastStyleTransfer&#xff08;快速風格遷移&#xff0c;Johnson et al.,…

C#Halcon從零開發_Day14_AOI缺陷檢測策略1_Bolb分析+特征分析_餅干破損檢測

一、引言 *缺陷檢測策略1&#xff1a;Blob分析特征分析 *Blob分析&#xff1a;閾值分割、開閉運算 (1) 圖像預處理 目的&#xff1a;增強目標與背景的對比度&#xff0c;抑制噪聲。 常用算子&#xff1a; threshold()&#xff1a;通過閾值分割將圖像轉換為二值圖像。 mean_…