首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java 對象內存佈局:外部對象引用內部對象(如 String)在堆中的存儲關係

     編輯:程式設計綜合問答

結論先行

A a = new A(); 在堆中分配 A 實例,棧上變量 a 存儲**引用(地址)**。
若 A 類包含 String name; 字段,則 A 實例內部存儲 name 字段的**引用**,指向堆中(或常量池中)獨立的 String 對象。

內存圖解

棧帧 (main)
+-----------------+
| a (引用)  ──────┼──▶ 堆
+-----------------+     +---------------------+
                        | A 實例              |
                        | +-----------------+ |
                        | | name (引用)  ───┼───▶ 堆/常量池
                        | | other fields... | |     +---------------------+
                        | +-----------------+ |     | String "Hello"      |
                        +---------------------+     | char[] value [...]  |
                                                   | int hash = ...      |
                                                   +---------------------+

關鍵細節

  • String 對象位置:
    - 字面量 "Hello" → **字符串常量池**(方法區/元空間,JDK 7+ 在堆)。
    - new String("Hello") / 運行時拼接 → **堆**。
  • 引用大小:64 位 JVM 默認開啟壓縮指針 (-XX:+UseCompressedOops),引用佔 **4 字節**;關閉時 8 字節。
  • 對象頭:每個堆對象包含 Mark Word (8/16 字節) + Klass Pointer (4/8 字節),數組額外有長度字段。
  • 字段排列:JVM 會重排序字段以優化對齊(long/double 8 字節對齊,int/float 4 字節,引用 4/8 字節,boolean/byte 1 字節),非 @Contended 時不保證聲明順序。

驗證代碼 (JOL - Java Object Layout)

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

public class Demo {
    static class A { String name; int age; }
    public static void main(String[] args) {
        A a = new A(); a.name = "Hello"; a.age = 25;
        System.out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}
// 輸出示例:
// A object internals:
//  OFFSET  SIZE   TYPE DESCRIPTION
//      0    12        (object header)
//     12     4   String A.name  ← 引用,4字節
//     16     4     int A.age
//     20     4        (alignment padding)
// Instance size: 24 bytes

常見誤區

  • 「對象裡直接包含另一個對象」—— **錯**。Java 無值類型(除基本類型、record/value class 預覽特性),**只有引用**。
  • 「String 在常量池,所以不佔堆」—— **不全對**。字面量在常量池,但 new String()、substring() (JDK 7+)、拼接結果在堆。

理解「引用鏈:棧變量 → 堆對象 → 引用字段 → 另一堆對象/常量池」,是排查 OOM、優化內存佔用、分析 JOL 輸出的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved