最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

動(dòng)手觀(guān)察java對(duì)象內(nèi)存大?。ɑ?4位操作系統(tǒng))

2023-02-19 15:19 作者:會(huì)燒菜的沙師弟  | 我要投稿

引言

hello,大家好,我是小面!今天有個(gè)小伙伴私信我說(shuō)怎么能親眼看見(jiàn)java對(duì)象占用的大小呢?那小面就這個(gè)問(wèn)題做一個(gè)簡(jiǎn)單的實(shí)驗(yàn)來(lái),基于64位操作系統(tǒng)來(lái)看看對(duì)象的大小。

在開(kāi)始實(shí)驗(yàn)之前,也有一些老生常談的知識(shí)需要鋪墊一下。

查看虛擬機(jī)配置

通過(guò)-xx參數(shù) PrintCommandLineFlags查看


那么我們看到了一堆輸出參數(shù),參數(shù)前面帶有-XX,-XX是指什么呢?

這個(gè)是JVM為我們提供了三種參數(shù)方式(標(biāo)準(zhǔn)選項(xiàng)、X選項(xiàng)、XX選項(xiàng))

標(biāo)準(zhǔn)選項(xiàng)

這類(lèi)選項(xiàng)功能是非常穩(wěn)定的,在后續(xù)jdk版本中也不太會(huì)發(fā)生變化。

在cmd終端運(yùn)行java、 java -help 就可以看到所有的標(biāo)準(zhǔn)選項(xiàng)。

所有的標(biāo)準(zhǔn)選項(xiàng)都是以 - 開(kāi)頭,例如-version,-server等。

X選項(xiàng)

這類(lèi)選項(xiàng)功能還是很穩(wěn)定,后續(xù)版本中可能會(huì)改變,也有可能不再提供了。

運(yùn)行 java -X 命令可以看到所有的X選項(xiàng)。

這類(lèi)選項(xiàng)都是以 -X 開(kāi)頭,比如 -Xmx -Xms -Xmn -Xss。

XX選項(xiàng)

這類(lèi)選項(xiàng)是屬于實(shí)驗(yàn)性,主要是給JVM開(kāi)發(fā)者用于開(kāi)發(fā)和調(diào)試JVM的,后續(xù)的版本中有可能會(huì)變化。

如果是布爾類(lèi)型的選項(xiàng),它的格式為-XX:+flag或者-XX:-flag,分別表示開(kāi)啟和關(guān)閉該選項(xiàng)。

針對(duì)非布爾類(lèi)型的選項(xiàng),它的格式為-XX:flag=value

例如:

-XX:InitialHeapSize=132558400 #JVM初始堆內(nèi)存-XX:MaxHeapSize=2120934400 #JVM最大堆內(nèi)存-XX:+PrintCommandLineFlags-XX:+UseCompressedClassPointers-XX:+UseCompressedOops-XX:-UseLargePagesIndividualAllocation-XX:+UseParallelGC

其中有一項(xiàng)是UseCompressedClassPointers,這個(gè)叫開(kāi)啟指針壓縮

在HotSpot 虛擬機(jī)中,對(duì)象在內(nèi)存中布局分為三塊區(qū)域,對(duì)象頭(Header)、實(shí)例數(shù)據(jù)(Instance Data)和對(duì)齊填充(Padding),普通對(duì)象和數(shù)組對(duì)象又稍有差別,我們一起來(lái)看一看。

普通對(duì)象

  1. 對(duì)象頭:markword 8個(gè)字節(jié)

  2. ClassPointer指針:-XX:+UseCompressedClassPointers 大小為4字節(jié) -XX:-UseCompressedClassPointers不開(kāi)啟為8字節(jié)。表示是否啟用類(lèi)指針壓縮,因?yàn)閷?duì)于任何一個(gè)jvm中的對(duì)象而言,其內(nèi)部都有一個(gè)指向自己對(duì)應(yīng)類(lèi)(屬于哪個(gè)class)的指針(Java習(xí)慣叫引用),在64位的Java虛擬機(jī)中,默認(rèn)是啟動(dòng)壓縮的

  3. 實(shí)例數(shù)據(jù)
    引用類(lèi)型:-XX:+UseCompressedOops 大小為4字節(jié) -XX:-UseCompressedOops不開(kāi)啟為8字節(jié)
    表示是否使用普通對(duì)象指針壓縮,Oops是Ordinary object pointers的縮寫(xiě),就是任何指向一個(gè)在堆中的對(duì)象(非簡(jiǎn)單類(lèi)型)的指針,默認(rèn)也是啟動(dòng)壓縮的

  4. Padding對(duì)齊,8的倍數(shù)(加上這個(gè)對(duì)齊的字節(jié)就是整個(gè)對(duì)象的大小,大小是8的倍數(shù))

數(shù)組對(duì)象

  1. 對(duì)象頭:markword 8個(gè)字節(jié)

  2. ClassPointer指針同上

  3. 數(shù)組長(zhǎng)度:4字節(jié)

  4. 數(shù)組數(shù)據(jù)

  5. 對(duì)齊 8的倍數(shù)(加上這個(gè)對(duì)齊的字節(jié)就是整個(gè)對(duì)象的大小,大小是8的倍數(shù))

可以看見(jiàn),數(shù)組對(duì)象比普通對(duì)象多了一個(gè)數(shù)組長(zhǎng)度對(duì)象,另外普通對(duì)象和數(shù)組對(duì)象都是有對(duì)象頭的,我們來(lái)看下對(duì)象頭。

對(duì)象頭

對(duì)象頭主要包括Mark Word,對(duì)象指針,數(shù)組長(zhǎng)度

Mark Word

Mark Word占用8字節(jié)空間,其主要用于鎖升級(jí)。 ? ?無(wú)鎖:Mark Word保存對(duì)象HashCode,鎖標(biāo)志位是01,是否偏向鎖為0。 ? ?偏向鎖:請(qǐng)求進(jìn)來(lái)先檢查是否包括線(xiàn)程id,沒(méi)有的話(huà)保存線(xiàn)程id,修改是否偏向鎖標(biāo)識(shí)。如果包括線(xiàn)程id,則判斷線(xiàn)程id是否是本線(xiàn)程id,是的話(huà)繼續(xù)向下執(zhí)行,不是的則進(jìn)行搶鎖操作,搶鎖成功更改線(xiàn)程id,失敗則升級(jí)為輕量級(jí)鎖。 ? ?輕量級(jí)鎖:偏向鎖搶奪失敗后升級(jí)為輕量級(jí)鎖,jvm通過(guò)cas操作在當(dāng)前線(xiàn)程的線(xiàn)程棧中開(kāi)辟一塊單獨(dú)的空間保存指向?qū)ο箧iMark Word的指針,并且在對(duì)象鎖Mark Word中保存指向這片空間的指針,如果保存成功,則表示當(dāng)前線(xiàn)程搶到鎖,繼續(xù)執(zhí)行。保存失敗則表示搶鎖失敗。 ? ?輕量級(jí)鎖搶鎖失敗JVM使用自旋鎖不斷重試搶鎖避免線(xiàn)程阻塞,當(dāng)達(dá)到一定次數(shù)后(jdk1.7后JVM控制自旋次數(shù)),升級(jí)為重量級(jí)鎖。 ? -XX:-UseSpinning ?控制是否開(kāi)啟自旋鎖,默認(rèn)開(kāi)啟 ? ?重量級(jí)鎖: 自旋鎖自旋一定次數(shù)還沒(méi)獲得鎖則升級(jí)為重量級(jí)鎖,此時(shí)只有獲取到鎖的線(xiàn)程能執(zhí)行,其余線(xiàn)程阻塞。

對(duì)于對(duì)象有了一個(gè)初步的認(rèn)識(shí)后,小面將通過(guò)一個(gè)小實(shí)驗(yàn)來(lái)觀(guān)測(cè)對(duì)象的大小,讓大家有一個(gè)實(shí)質(zhì)性的感受。

實(shí)驗(yàn)(觀(guān)察對(duì)象的大?。?/h1>
  1. 新建項(xiàng)目(以IDEA為例)ObjectSize (1.8)一個(gè)單獨(dú)的項(xiàng)目


  1. 創(chuàng)建文件ObjectSizeAgent

import java.lang.instrument.Instrumentation;public class ObjectSizeAgent { ? ?private static Instrumentation inst; ? ?public static void premain(String agentArgs, Instrumentation _inst) { ? ? ? ?inst = _inst; ? ?} ? ?public static long sizeOf(Object o) { ? ? ? ?return inst.getObjectSize(o); ? ?} }

  1. src目錄下創(chuàng)建META-INF/MANIFEST.MF

    Manifest-Version: 1.0Created-By: lnf.com Premain-Class: com.lnf.ObjectSizeAgent

  1. 注意Premain-Class這行必須是新的一行(回車(chē) + 換行),確認(rèn)idea不能有任何錯(cuò)誤提示
    pom打包設(shè)置:

<build> ? ? ? ?<plugins> ? ? ? ? ? ?<plugin> ? ? ? ? ? ? ? ?<groupId>org.apache.maven.plugins</groupId> ? ? ? ? ? ? ? ?<artifactId>maven-jar-plugin</artifactId> ? ? ? ? ? ? ? ?<version>3.1.0</version> ? ? ? ? ? ? ? ?<configuration> ? ? ? ? ? ? ? ? ? ?<archive> ? ? ? ? ? ? ? ? ? ? ? ?<manifestEntries> ? ? ? ? ? ? ? ? ? ? ? ? ? ?<Premain-Class>com.lnf.ObjectSizeAgent</Premain-Class> ? ? ? ? ? ? ? ? ? ? ? ? ? ?<Agent-Class>com.lnf.ObjectSizeAgent</Agent-Class> ? ? ? ? ? ? ? ? ? ? ? ? ? ?<Can-Redefine-Classes>true</Can-Redefine-Classes> ? ? ? ? ? ? ? ? ? ? ? ? ? ?<Can-Retransform-Classes>true</Can-Retransform-Classes> ? ? ? ? ? ? ? ? ? ? ? ?</manifestEntries> ? ? ? ? ? ? ? ? ? ?</archive> ? ? ? ? ? ? ? ?</configuration> ? ? ? ? ? ?</plugin> ? ? ? ?</plugins> ? ?</build>

  1. 打包jar文件

  1. 創(chuàng)建測(cè)量類(lèi):

import com.lnf.jvm.agent.ObjectSizeAgent; ? public class T03_SizeOfAnObject { ? ? ? public static void main(String[] args) { ? ? ? ? ? System.out.println(ObjectSizeAgent.sizeOf(new Object())); ? ? ? ? ? System.out.println(ObjectSizeAgent.sizeOf(new int[] {})); ? ? ? ? ? System.out.println(ObjectSizeAgent.sizeOf(new P())); ? ? ? } ? ? ? private static class P { ? ? ? ? ? ? ? ? ? ? ? ? ? //8 _markword ? ? ? ? ? ? ? ? ? ? ? ? ? //4 _oop指針 ? ? ? ? ? int id; ? ? ? ? //4 ? ? ? ? ? String name; ? ?//4 ? ? ? ? ? int age; ? ? ? ?//4 ? ? ? ? ? byte b1; ? ? ? ?//1 ? ? ? ? ? byte b2; ? ? ? ?//1 ? ? ? ? ? Object o; ? ? ? //4 ? ? ? ? ? byte b3; ? ? ? ?//1 ? ? ? } ? }

  1. 在需要使用該Agent Jar的項(xiàng)目中引入該Jar包
    project structure - project settings - library 添加該jar包


7. 運(yùn)行時(shí)需要該Agent Jar的類(lèi),加入?yún)?shù):

-javaagent:E:\java\test\ObjectSize\target\ObjectSize-1.0-SNAPSHOT.jar

不開(kāi)啟壓縮指針,減號(hào)就表示不開(kāi)啟

-javaagent:E:\java\test\ObjectSize\target\ObjectSize-1.0-SNAPSHOT.jar -XX:-UseCompressedClassPointers

指定把哪個(gè)jar文件當(dāng)成我這次運(yùn)行的虛擬機(jī)

  1. 運(yùn)行測(cè)量類(lèi):

import com.lnf.jvm.agent.ObjectSizeAgent; ? public class T03_SizeOfAnObject { ? ? ? public static void main(String[] args) { ? ? ? ? ? System.out.println(ObjectSizeAgent.sizeOf(new Object())); ? ? ? ? ? System.out.println(ObjectSizeAgent.sizeOf(new int[] {})); ? ? ? ? ? System.out.println(ObjectSizeAgent.sizeOf(new P())); ? ? ? } ? ? ? private static class P { ? ? ? ? ? ? ? ? ? ? ? ? ? //8 _markword ? ? ? ? ? ? ? ? ? ? ? ? ? //4 _oop指針 ? ? ? ? ? int id; ? ? ? ? //4 ? ? ? ? ? String name; ? ?//4 ? ? ? ? ? int age; ? ? ? ?//4 ? ? ? ? ? byte b1; ? ? ? ?//1 ? ? ? ? ? byte b2; ? ? ? ?//1 ? ? ? ? ? Object o; ? ? ? //4 ? ? ? ? ? byte b3; ? ? ? ?//1 ? ? ? } ? }

new Object()的長(zhǎng)度16 = 對(duì)象頭8+指針(不開(kāi)啟指針壓縮長(zhǎng)度是8)4 + padding 4

new int[] 的長(zhǎng)度 = 對(duì)象頭8+指針(不開(kāi)啟指針壓縮長(zhǎng)度是8)4 + int類(lèi)型 4 + padding 0(長(zhǎng)度正好16是8的2倍)

那么這里開(kāi)啟指針壓縮,我們也可不開(kāi)啟指針壓縮,通過(guò)JVM參數(shù)

-javaagent:E:\java\test\ObjectSize\target\ObjectSize-1.0-SNAPSHOT.jar -XX:-UseCompressedClassPointers

-XX:-UseCompressedClassPointers不開(kāi)啟指針壓縮來(lái)看下運(yùn)行結(jié)果

大家可以自行算一下,不開(kāi)啟壓縮就是8個(gè)字節(jié)

總結(jié)

實(shí)驗(yàn)到這就結(jié)束了,相信大家通過(guò)這個(gè)小實(shí)驗(yàn)可以認(rèn)識(shí)到一個(gè)對(duì)象在JVM內(nèi)存中的布局。大家可以動(dòng)手自己試一試,利用javaagent實(shí)測(cè)java對(duì)象大小。


動(dòng)手觀(guān)察java對(duì)象內(nèi)存大?。ɑ?4位操作系統(tǒng))的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
垦利县| 金华市| 崇左市| 五华县| 石嘴山市| 万州区| 赫章县| 宝兴县| 和林格尔县| 扬州市| 六盘水市| 中卫市| 响水县| 洮南市| 栾川县| 封开县| 任丘市| 化德县| 滦平县| 喀喇沁旗| 新野县| 南召县| 稻城县| 郴州市| 康平县| 丹棱县| 泰安市| 五莲县| 鹤峰县| 安图县| 定边县| 田东县| 太原市| 昭通市| 乌拉特中旗| 文昌市| 大庆市| 阳朔县| 富蕴县| 松溪县| 大渡口区|