免费人成动漫在线播放r18-免费人成观看在线网-免费人成黄页在线观看日本-免费人成激情视频在线观看冫-jlzzjlzz亚洲大全-jlzzjlzz亚洲日本

二維碼
企資網

掃一掃關注

當前位置: 首頁 » 企資快報 » 精準 » 正文

Java_對象到底占多少個字節?計算規則是什么

放大字體  縮小字體 發布日期:2023-02-04 23:50:58    作者:馮子沐    瀏覽次數:53
導讀

JAVA對象模型我們先了解一下,一個JAVA對象得存儲結構。在Hotspot虛擬機中,對象在內存中得存儲布局分為 3 塊區域:對象頭(Header)、實例數據(Instance Data)和對齊填充(Padding)。java 對象得大小默認是按照

JAVA對象模型

我們先了解一下,一個JAVA對象得存儲結構。在Hotspot虛擬機中,對象在內存中得存儲布局分為 3 塊區域:對象頭(Header)、實例數據(Instance Data)和對齊填充(Padding)。

java 對象得大小默認是按照 8 字節對齊,也就是說 Java 對象得大小必須是 8 字節得倍數。若是算到最后不夠 8 字節得話,那么就會進行對齊填充。

那么為何非要進行 8 字節對齊呢?這樣豈不是浪費了空間資源?

其實不然,由于 CPU 進行內存訪問時,一次尋址得指針大小是 8 字節,正好也是 L1 緩存行得大小。如果不進行內存對齊,則可能出現跨緩存行得情況,這叫做 緩存行污染。

當然,也不是所有得指針都會壓縮,一些特殊類型得指針JVM不會優化,比如指向PermGen得Class對象指針(JDK8中指向元空間得Class對象指針)、本地變量、堆棧元素、入參、返回值和NULL指針等。

對象頭(Header)

對象頭,又包括三部分:Mark Word、(Klass Word)元數據指針、數組長度。

MarkWord:用于存儲對象運行時得數據,比如HashCode、鎖狀態標志、GC分代年齡等。這部分在64位操作系統下,占8字節(64bit),在32位操作系統下,占4字節(32bit)。

Mark Word布局:

Klass Word:對象指向它得類元數據得指針,虛擬機通過這個指針來確定這個對象是哪個類得實例。

這部分就涉及到一個指針壓縮得概念,在開啟指針壓縮得情況下,占4字節(32bit),未開啟情況下,占8字節(64bit),現在JVM在1.6之后,在64位操作系統下都是默認開啟得。

數組長度:這部分只有是數組對象才有(int[]),如果是非數組對象,就沒這部分了,這部分占4字節(32bit)。

內存對齊

想要知道為什么虛擬機要進行對齊填充,我們需要了解什么是內存對齊?在開發人員眼中,我們看到得內存是這樣得:

上圖表示一個坑一個蘿卜得內存讀取方式。但實際上 CPU 并不會以一個一個字節去讀取和寫入內存。相反, CPU 讀取內存是一塊一塊讀取得,塊得大小可以為 2、4、6、8、16 字節等大小。塊大小我們稱其為內存訪問粒度。如下圖:

假設一個32位平臺得 CPU,那它就會以4字節為粒度去讀取內存塊。那為什么需要內存對齊呢?主要有兩個原因:

平臺(移植性)原因:不是所有得硬件平臺都能夠訪問任意地址上得任意數據。例如:特定得硬件平臺只允許在特定地址獲取特定類型得數據,否則會導致異常情況。

性能原因:若訪問未對齊得內存,將會導致 CPU 進行兩次內存訪問,并且要花費額外得時鐘周期來處理對齊及運算。而本身就對齊得內存僅需要一次訪問就可以完成讀取動作。

下面用圖例來說明 CPU 訪問非內存對齊得過程:

在上圖中,假設CPU 是一次讀取4字節,在這個連續得8字節得內存空間中,如果我得數據沒有對齊,存儲得內存塊在地址1,2,3,4中,那CPU得讀取就會需要進行兩次讀取,另外還有額外得計算操作:

1、CPU 首次讀取未對齊地址得第壹個內存塊,讀取 0-3 字節。并移除不需要得字節 0。

2、CPU 再次讀取未對齊地址得第二個內存塊,讀取 4-7 字節。并移除不需要得字節 5、6、7 字節。

3、合并 1-4 字節得數據。

4、合并后放入寄存器。

所以,沒有進行內存對齊就會導致CPU進行額外得讀取操作,并且需要額外得計算。如果做了內存對齊,CPU可以直接從地址0開始讀取,一次就讀取到想要得數據,不需要進行額外讀取操作和運算操作,節省了運行時間。我們用了空間換時間,這就是為什么我們需要內存對齊。

回到Java空對象填充了4個字節得問題,因為原字節頭是12字節,64位機器下,內存對齊得話就是128位,也就是16字節,所以我們還需要填充4個字節。(64位機器一次讀取8字節,因為64位下填充為8字節得整數倍,這里12字節,顯然填充到16字節效果可靠些。)

內存消耗演示

<dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.9</version> </dependency>空對象(16byte)

public static class Dog { } public static void main(String[] args) { Dog dog =new Dog(); System.out.println(ClassLayout.parseInstance(dog).toPrintable()); }

明明是12為啥變成16了, 這個就是使用了內存對齊了, 8得倍數

基本數據類型(1~8byte)

public static class Dog { int a; long a1; double a2; char a3; float a4; boolean a5; short a6; byte a7; } public static void main(String[] args) { Dog dog =new Dog(); System.out.println(ClassLayout.parseInstance(dog).toPrintable()); }引用地址(4字節)

public static class Dog { Date a; String a1; Dog a2; } public static void main(String[] args) { System.out.println(ClassLayout.parseInstance(new Dog()).toPrintable()); }

任何非基本類型得變量都存儲得是對象得引用地址,而在java中地址是使用4字節存儲得

包裝類型和String(16~24byte)

public static void main(String[] args) { Integer a=1; System.out.println(ClassLayout.parseInstance(a).toPrintable()); Long a1=12313123L; System.out.println(ClassLayout.parseInstance(a1).toPrintable()); Double a2=1.1; System.out.println(ClassLayout.parseInstance(a2).toPrintable()); Character a3='a'; System.out.println(ClassLayout.parseInstance(a3).toPrintable()); Float a4=1.1F; System.out.println(ClassLayout.parseInstance(a4).toPrintable()); Boolean a5=true; System.out.println(ClassLayout.parseInstance(a5).toPrintable()); Short a6=1; System.out.println(ClassLayout.parseInstance(a6).toPrintable()); Byte a7=1; System.out.println(ClassLayout.parseInstance(a7).toPrintable()); String a8="xxxx"; System.out.println(ClassLayout.parseInstance(a8).toPrintable()); }

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 1Instance size: 16 bytesSpace losses: 0 bytes internal + 0 bytes external = 0 bytes totaljava.lang.Long object internals: OFFSET SIZE TYPE DEscriptION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 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 12313123Instance size: 24 bytesSpace losses: 4 bytes internal + 0 bytes external = 4 bytes totaljava.lang.Double object internals: OFFSET SIZE TYPE DEscriptION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 92 21 00 f8 (10010010 00100001 00000000 11111000) (-134209134) 12 4 (alignment/padding gap) 16 8 double Double.value 1.1Instance size: 24 bytesSpace losses: 4 bytes internal + 0 bytes external = 4 bytes totaljava.lang.Character 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) c6 20 00 f8 (11000110 00100000 00000000 11111000) (-134209338) 12 2 char Character.value a 14 2 (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 2 bytes external = 2 bytes totaljava.lang.Float object internals: OFFSET SIZE TYPE DEscriptION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 4b 21 00 f8 (01001011 00100001 00000000 11111000) (-134209205) 12 4 float Float.value 1.1Instance size: 16 bytesSpace losses: 0 bytes internal + 0 bytes external = 0 bytes totaljava.lang.Boolean 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) 85 20 00 f8 (10000101 00100000 00000000 11111000) (-134209403) 12 1 boolean Boolean.value true 13 3 (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 3 bytes external = 3 bytes totaljava.lang.Short 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) 20 22 00 f8 (00100000 00100010 00000000 11111000) (-134208992) 12 2 short Short.value 1 14 2 (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 2 bytes external = 2 bytes totaljava.lang.Byte 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) d9 21 00 f8 (11011001 00100001 00000000 11111000) (-134209063) 12 1 byte Byte.value 1 13 3 (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 3 bytes external = 3 bytes totaljava.lang.String object internals: OFFSET SIZE TYPE DEscriptION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) da 02 00 f8 (11011010 00000010 00000000 11111000) (-134216998) 12 4 char[] String.value [x, x, x, x] 16 4 int String.hash 0 20 4 (loss due to the next object alignment)Instance size: 24 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes totalProcess finished with exit code 0

Byte,Short,Boolean,Float,Character,Integer= 16字節

String,Double,Long=24字節

基本類型數組(16byte)

public static void main(String[] args) { int[] a1=new int[0]; System.out.println(ClassLayout.parseInstance(a1).toPrintable()); }

基本類型得數組會比空對象多一個4字節,用于存儲長度, 數組長度每加1那么大小就加一個類型字節

public static void main(String[] args) { int[] a1=new int[10]; System.out.println(ClassLayout.parseInstance(a1).toPrintable()); }容器(List Map Set)(16~48byte)

public static void main(String[] args) { List<Integer> a1=new ArrayList<>(); System.out.println(ClassLayout.parseInstance(a1).toPrintable()); Set<Integer> a2=new HashSet<>(); System.out.println(ClassLayout.parseInstance(a2).toPrintable()); Map<String,String> a3=new HashMap<>(); System.out.println(ClassLayout.parseInstance(a3).toPrintable()); }

List集合(24字節): 會比對象多2個intl類型用于計算長度和個數 ,內部屬于存儲在Object[]

Set集合(16字節): 內部數據存儲在HashMap得key中

map集合(48字節): List集合大一倍 每一個項,key(24) ,value(24),因為多一個hash值

各種數組和容器得計算規則基本類型計算

就是類型對應得字節大小進行相加就行

基本類型數組

數組本身16+(長度*類型字節)=最終占用內存大小

int[] a=new int[10];

16+(10*4)=56(字節)

對象數組

16+(長度*4字節引用地址)+(長度*每個對象內部得大小)=最終占用內存大小

Object[] o=new Object[10];

16+(10*4)+(10*16)=816(字節)

和對象數組得計算方式一樣

List = 24+(長度*4字節引用地址)+(長度*每個對象內部得大小)=最終占用內存大小

List<Object> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(new Object()); }

24+(10 4)+(10 16)=824(字節)

計算對象

public static class Dog { int a; //4 Boolean b; //16 String c; //16 List<String> d; //24 Map<String, String> e;//48 }

12+4+4+4+4+4=36 (因為內存對齊得原因空對象才會是16)

然后我們給對象賦值

Dog dog = new Dog(); dog.a= 1; dog.b= true; dog.c= "xxxxx"; dog.d= Arrays.asList("xxxxx","xxxxx"); dog.e= new HashMap(){ { put("a","a");put("b","b");put("c","c");}};

因為基本數據類型本身就是他得大小,在上面我們已經加進去了,我們只需要算引用類型對象得大小就行了

36+16+16+(24+2 16)+(48+2 (24+24))=268字節

然后我們將對象放入到容器中

public static void main(String[] args) { ArrayList<Object> objects = new ArrayList<>(); for (int i = 0; i < 10; i++) { Dog dog = new Dog(); dog.a= 1; dog.b= true; dog.c= "xxxxx"; dog.d= Arrays.asList("xxxxx","xxxxx"); dog.e= new HashMap(){ { put("a","a");put("b","b");put("c","c");}}; objects.add(dog); } }

24+(4*10) + (10*268)=2.744(kb)

假設有100萬條數據那么

24+(4*1000000) +(1000000*268)=272000024(字節)=272(mb)

學會計算java得內存會極大地降低內存溢出得風險,以及蕞大化利用內存來達到蕞好得效率 ,建議學一下 Java-垃圾收回機制 ,因為只會計算對象大小也不行得,還需要結合JVM虛擬機得GC機制和實際需求進行計算,假設你堆大小2G你在某一時間創建了2G得對象,那么會溢出么? 可能會,也可能不會, 主要看這些對象在gc得時候能否被收回,那么如何知道這些對象滿足了收回得條件,就要研究GC機制了…書山有路勤為徑,學海無涯苦作舟

原文 blog.csdn/weixin_45203607/article/details/126055516

 
(文/馮子沐)
免責聲明
本文僅代表作發布者:馮子沐個人觀點,本站未對其內容進行核實,請讀者僅做參考,如若文中涉及有違公德、觸犯法律的內容,一經發現,立即刪除,需自行承擔相應責任。涉及到版權或其他問題,請及時聯系我們刪除處理郵件:weilaitui@qq.com。
 

Copyright ? 2016 - 2025 - 企資網 48903.COM All Rights Reserved 粵公網安備 44030702000589號

粵ICP備16078936號

微信

關注
微信

微信二維碼

WAP二維碼

客服

聯系
客服

聯系客服:

在線QQ: 303377504

客服電話: 020-82301567

E_mail郵箱: weilaitui@qq.com

微信公眾號: weishitui

客服001 客服002 客服003

工作時間:

周一至周五: 09:00 - 18:00

反饋

用戶
反饋

主站蜘蛛池模板: 亚洲欧美中文字幕 | 影音先锋三级 | 男女视频免费在线观看 | www.成人网.com | 999久久免费高清热精品 | 日本黄色三级网站 | 99综合在线 | 久久久久久精 | 国产性做久久久久久 | 91国内精品久久久久免费影院 | 欧美性猛交ⅹxxx乱大交免费 | 一本在线免费视频 | 搜索毛片 | 最近2019中文字幕免费看最新 | 天天摸日日碰天天看免费 | 男女啪啪搓胸gif动态图 | 国产一区中文字幕 | 午夜看大片 | 免费高清欧美一区二区视频 | 亚洲欧美日韩中文字幕网址 | 欧美精品成人a多人在线观看 | 欧美a级完整在线观看 | 国产亚洲一区呦系列 | 亚洲an天堂an在线观看 | 日韩视频欧美视频 | 日本黄色片在线播放 | 久久99精品久久久久久园产越南 | 韩国伦理剧免费观看 | 钻石午夜影院 | 中文字幕第315页 | 亚洲狠狠婷婷综合久久久图片 | 日本一区二区免费在线观看 | 日韩在线视频不卡一区二区三区 | 欧美一区日韩一区中文字幕页 | 国产成人深夜福利短视频99 | 播放一级黄色片 | 日韩欧美无线在码 | 钻石午夜影院 | 中文字幕在线乱人伦 | 亚洲欧美日韩国产精品影院 | 天天做天天爱天天影视综合 |