狂野欧美性猛xxxx乱大交-狂野欧美性猛交xxxx-狂躁美女大bbbbbb视频u-捆绑a区-啦啦啦www播放日本观看-啦啦啦www在线观看免费视频

二維碼
企資網(wǎng)

掃一掃關(guān)注

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

Java_對象到底占多少個字節(jié)?計算規(guī)則是什么

放大字體  縮小字體 發(fā)布日期:2023-02-04 23:50:58    作者:馮子沐    瀏覽次數(shù):62
導讀

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

JAVA對象模型

我們先了解一下,一個JAVA對象得存儲結(jié)構(gòu)。在Hotspot虛擬機中,對象在內(nèi)存中得存儲布局分為 3 塊區(qū)域:對象頭(Header)、實例數(shù)據(jù)(Instance Data)和對齊填充(Padding)。

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

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

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

當然,也不是所有得指針都會壓縮,一些特殊類型得指針JVM不會優(yōu)化,比如指向PermGen得Class對象指針(JDK8中指向元空間得Class對象指針)、本地變量、堆棧元素、入?yún)ⅰ⒎祷刂岛蚇ULL指針等。

對象頭(Header)

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

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

Mark Word布局:

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

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

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

內(nèi)存對齊

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

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

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

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

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

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

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

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

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

3、合并 1-4 字節(jié)得數(shù)據(jù)。

4、合并后放入寄存器。

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

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

內(nèi)存消耗演示

<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了, 這個就是使用了內(nèi)存對齊了, 8得倍數(shù)

基本數(shù)據(jù)類型(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字節(jié))

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字節(jié)存儲得

包裝類型和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字節(jié)

String,Double,Long=24字節(jié)

基本類型數(shù)組(16byte)

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

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

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字節(jié)): 會比對象多2個intl類型用于計算長度和個數(shù) ,內(nèi)部屬于存儲在Object[]

Set集合(16字節(jié)): 內(nèi)部數(shù)據(jù)存儲在HashMap得key中

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

各種數(shù)組和容器得計算規(guī)則基本類型計算

就是類型對應(yīng)得字節(jié)大小進行相加就行

基本類型數(shù)組

數(shù)組本身16+(長度*類型字節(jié))=最終占用內(nèi)存大小

int[] a=new int[10];

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

對象數(shù)組

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

Object[] o=new Object[10];

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

和對象數(shù)組得計算方式一樣

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

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

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

計算對象

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 (因為內(nèi)存對齊得原因空對象才會是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");}};

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

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

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

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)

假設(shè)有100萬條數(shù)據(jù)那么

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

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

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

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

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

粵ICP備16078936號

微信

關(guān)注
微信

微信二維碼

WAP二維碼

客服

聯(lián)系
客服

聯(lián)系客服:

在線QQ: 303377504

客服電話: 020-82301567

E_mail郵箱: weilaitui@qq.com

微信公眾號: weishitui

客服001 客服002 客服003

工作時間:

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

反饋

用戶
反饋

主站蜘蛛池模板: 99精品国产第一福利网站 | 九九在线偷拍视频在线播放 | 日本综合在线 | 欧美一级毛片欧美一级无片 | 国产成人亚综合91精品首页 | 91亚洲国产系列精品第56页 | 狼人综合伊人 | 天天操天天透 | 欧美成人在线免费视频 | 久99久爱精品免费观看视频 | 四虎成人国产精品视频 | 奇米影视778成人四色狠狠 | 日韩中文字幕在线观看 | 日本a免费观看 | 久久99国产亚洲精品 | 亚洲女人国产香蕉久久精品 | 国产伊人影院 | 欧美亚洲另类视频 | 国产精品400部自产在线观看 | 欧美理论在线观看 | 亚洲国产成人最新精品资源 | 亚洲女bbwxxxx另类 | 精品在线视频观看 | 一区二区在线精品免费视频 | 青青草一区二区免费精品 | 黄色在线视频网 | 久久影院朴妮唛 | 久久香蕉国产线看观看乱码 | 四虎永久地址4hu2019 | 国产精品一区伦免视频播放 | 国产中文字幕在线观看 | 七次郎在线视频精品视频 | 97s色视频一区二区三区在线 | 在线播放人成午夜免费视频 | 国产欧美日韩高清专区手机版 | 91精品综合久久久久m3u8 | 人人干夜夜操 | 97国产在线视频公开免费 | 久久国产大片 | 免费在线激情视频 | 亚洲综合久久久 |