java object多大 java对象内存模型 数组有多长
https://www.cnblogs.com/maxigang/p/9040088.html
https://www.jianshu.com/p/91e398d5d17c
對象結構
在HotSpot虛擬機中,對象在內存中存儲的布局可以分為3塊區域:對象頭(Header)、實例數據(Instance Data)和對齊填充(Padding)。下圖是普通對象實例與數組對象實例的數據結構:
1 對象頭
HotSpot虛擬機的對象頭包括兩部分信息:
markword
第一部分markword,用于存儲對象自身的運行時數據,如哈希碼(HashCode)、GC分代年齡、鎖狀態標志、線程持有的鎖、偏向線程ID、偏向時間戳等,這部分數據的長度在32位和64位的虛擬機(未開啟壓縮指針)中分別為32bit和64bit,官方稱它為“MarkWord”。
klass
對象頭的另外一部分是klass類型指針,即對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例. 32位4字節,64位開啟指針壓縮或最大堆內存<32g時 4字節,否則8字節
數組長度(只有數組對象有) 4字節
如果對象是一個數組, 那在對象頭中還必須有一塊數據用于記錄數組長度.int最大值2g,2^31,java數組(包含字符串)最長2g
2 實例數據
實例數據部分是對象真正存儲的有效信息,也是在程序代碼中所定義的各種類型的字段內容。無論是從父類繼承下來的,還是在子類中定義的,都需要記錄起來。
| Primitive Type | Memory Required(bytes) |
|---|---|
| boolean | 1 |
| byte | 1 |
| short | 2 |
| char | 2 |
| int | 4 |
| float | 4 |
| long | 8 |
| double | 8 |
此外,引用類型在32位系統上每個占用4B, 在64位系統上每個占用8B,開啟(默認)指針壓縮占用4B
3 對齊填充
第三部分對齊填充并不是必然存在的,也沒有特別的含義,它僅僅起著占位符的作用。由于HotSpot VM的自動內存管理系統要求對象起始地址必須是8字節的整數倍,換句話說,就是對象的大小必須是8字節的整數倍。而對象頭部分正好是8字節的倍數(1倍或者2倍),因此,當對象實例數據部分沒有對齊時,就需要通過對齊填充來補全。
對象大小計算
要點
1. 在32位系統下,存放Class指針的空間大小是4字節,MarkWord是4字節,對象頭為8字節。
2. 在64位系統下,存放Class指針的空間大小是8字節,MarkWord是8字節,對象頭為16字節。
3. 64位開啟指針壓縮或者 JVM 堆的最大值小于 32G的情況下,存放Class指針的空間大小是4字節,MarkWord是8字節,對象頭為12字節。
4 如果是數組對象,對象頭的大小為:數組對象頭8字節+數組長度4字節+對齊4字節=16字節。其中對象引用占4字節(未開啟指針壓縮的64位為8字節),數組MarkWord為4字節(64位未開啟指針壓縮的為8字節);
markword始終為8字節,class pointer及object ref pointer壓縮4字節,不壓縮8字節,數組對象的Shallow Size=數組對象頭(12/16)+數組長度4字節+length * 引用指針大小(4/8)+填充
5. 靜態屬性不算在對象大小內。
JDK 1.8,默認啟用指針壓縮參數就是開啟的。
補充:
HotSpot對象模型
HotSpot中采用了OOP-Klass模型,它是描述Java對象實例的模型,它分為兩部分:
類被加載到內存時,就被封裝成了klass,klass包含類的元數據信息,像類的方法、常量池這些信息都是存在klass里的,你可以認為它是java里面的java.lang.Class對象,記錄了類的全部信息;
OOP(Ordinary Object Pointer)指的是普通對象指針,它包含MarkWord 和元數據指針,MarkWord用來存儲當前指針指向的對象運行時的一些狀態數據;元數據指針則指向klass,用來告訴你當前指針指向的對象是什么類型,也就是使用哪個類來創建出來的;
那么為何要設計這樣一個一分為二的對象模型呢?這是因為HotSopt JVM的設計者不想讓每個對象中都含有一個vtable(虛函數表),所以就把對象模型拆成klass和oop,其中oop中不含有任何虛函數,而klass就含有虛函數表,可以進行method dispatch。
實踐結果:
public class MarkdownMain {
// 關閉指針壓縮-XX:-UseCompressedOops
public static void main(String []f) {
System.out.println(ClassLayout.parseInstance(new Integer(2)).toPrintable());
System.out.println(ClassLayout.parseInstance(new Long(2)).toPrintable());
System.out.println(ClassLayout.parseInstance(new MyLong()).toPrintable());
System.out.println(ClassLayout.parseInstance(new MyLong[]{new MyLong(), new MyLong(), new MyLong()}).toPrintable());
}
private static class MyLong {
public volatile long usefulVal;
public volatile Long anotherVal;
public MyRef myRef;
}
private static class MyRef {
Integer integer = new Integer(15);
}
}
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
1)1.8默認:開啟指針壓縮
java.lang.Integer object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 67 22 00 f8 (01100111 00100010 00000000 11111000) (-134208921)
12 4 int Integer.value 2
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
java.lang.Long object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) ae 22 00 f8 (10101110 00100010 00000000 11111000) (-134208850)
12 4 (alignment/padding gap)
16 8 long Long.value 2
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
markdown.MarkdownMain$MyLong object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 83 f2 00 f8 (10000011 11110010 00000000 11111000) (-134155645)
12 4 java.lang.Long MyLong.anotherVal null
16 8 long MyLong.usefulVal 0
24 4 markdown.MarkdownMain.MyRef MyLong.myRef null
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
[Lmarkdown.MarkdownMain$MyLong; object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 02 f3 00 f8 (00000010 11110011 00000000 11111000) (-134155518)
12 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3)
16 12 markdown.MarkdownMain$MyLong MarkdownMain$MyLong;.<elements> N/A
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
整個對象要是8的倍數,否則補全
markdown8字節,class pointer 4字節
引用類型4字節
數組類型的val中,存在【數組長度】個引用類型+數組長度int4
2)關閉指針壓縮
-XX:-UseCompressedOops
java.lang.Integer object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) d8 63 ac 10 (11011000 01100011 10101100 00010000) (279733208)
12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
16 4 int Integer.value 2
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Long object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 10 9f ac 10 (00010000 10011111 10101100 00010000) (279748368)
12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
16 8 long Long.value 2
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
markdown.MarkdownMain$MyLong object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 50 53 4f a3 (01010000 01010011 01001111 10100011) (-1555082416)
12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
16 8 long MyLong.usefulVal 0
24 8 java.lang.Long MyLong.anotherVal null
32 8 markdown.MarkdownMain.MyRef MyLong.myRef null
Instance size: 40 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
[Lmarkdown.MarkdownMain$MyLong; object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 28 5a 4f a3 (00101000 01011010 01001111 10100011) (-1555080664)
12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
16 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3)
20 4 (alignment/padding gap)
24 24 markdown.MarkdownMain$MyLong MarkdownMain$MyLong;.<elements> N/A
Instance size: 48 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
markdown8字節,class pointer 8字節
引用類型8字節
https://www.jianshu.com/p/91e398d5d17c 中介紹了另一種看對象模型的方式,還可以看Shallow Size和Retained Size
64位系統中,數組對象的對象頭占用24 bytes,啟用壓縮后占用16字節。比普通對象占用內存多是因為需要額外的空間存儲數組的長度?;A數據類型數組占用的空間包括數組對象頭以及基礎數據類型數據占用的內存空間。由于對象數組中存放的是對象的引用,所以數組對象的Shallow Size=數組對象頭(含數組長度4字節)+length * 引用指針大?。?/8字節)+填充,Retained Size=Shallow Size+length*每個元素的Retained Size。
有關Shallow Size和Retained Size請參考
使用MAT時的Shallow Size和 Retained Size的區別
鎖相關:
synchroned原理與對象頭(yet)
偽共享相關:
偽共享
總結
以上是生活随笔為你收集整理的java object多大 java对象内存模型 数组有多长的全部內容,希望文章能夠幫你解決所遇到的問題。