摘要:一個(gè)對(duì)象內(nèi)存有多大為什么想知道這個(gè),自以為很重要,其實(shí)。參考鏈接對(duì)象解析不得不了解的對(duì)象頭從開始在位系統(tǒng)上會(huì)默認(rèn)開啟壓縮指針研究位引用指針壓縮技術(shù)
java 一個(gè)對(duì)象內(nèi)存有多大
jdk: java 官網(wǎng)上下載的,HotSpot 虛擬機(jī)
java version "1.8.0_121" Java(TM) SE Runtime Environment (build 1.8.0_121-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
使用的方法: Instrumentation 參考的是 一個(gè)對(duì)象占用多少字節(jié)?
確認(rèn)編譯時(shí)是 32 位還是 64 位,對(duì)測(cè)試結(jié)果有影響。x86 為 32 位, amd64 為 64 位,其余我不知道
System.out.println(System.getProperty("os.arch"));準(zhǔn)備工作
SizeOfObject.java 直接從上面鏈接上拷貝
編譯這個(gè)類,得到 .class 文件
在包名路徑下執(zhí)行一下命令進(jìn)行打包(注意修改相應(yīng)的包名):
jar cvfm SizeOfObject.jar manifest.mf org/seal_de/SizeOfObject.class
其中 manifest.mf 清單信息為: PreMain-Class: org.seal_de.SizeOfObject
PS: 如果在打包好的 jar 包中,META-INF/MANIFEST.MF 沒有 PreMain-Class 屬性,添加上去即可
在運(yùn)行測(cè)試程序的時(shí)候,添加 vm 參數(shù)
-javaagent:{jar包路徑}SizeOfObject.jar測(cè)試用例
測(cè)試 int, Object, 引用的大小。其余類型測(cè)試都類似
public class MemoryTest { /** * -javaagent:{jar包路徑}SizeOfObject.jar -XX:+UseCompressedOops * 使用指針壓縮,在一定情況下64位HotSpot jvm默認(rèn)指針壓縮 * *Output: *amd64 *Object: 16 * *include one int: 16 *include two int: 24 *include three int: 24 * *include one object: 16 *include one object: 24 */ static void test1() { System.out.println(System.getProperty("os.arch")); System.out.printf("%-30s%9d ", "Object:", SizeOfObject.sizeOf(new Object())); System.out.println(); System.out.printf("%-30s%9d ", "include one int:", SizeOfObject.sizeOf(new IntegerTestOne())); System.out.printf("%-30s%9d ", "include two int:", SizeOfObject.sizeOf(new IntegerTestTwo())); System.out.printf("%-30s%9d ", "include three int:", SizeOfObject.sizeOf(new IntegerTestThree())); System.out.println(); System.out.printf("%-30s%9d ", "include one object:", SizeOfObject.sizeOf(new ReferenceTestOne())); System.out.printf("%-30s%9d ", "include one object:", SizeOfObject.sizeOf(new ReferenceTestTwo())); } /** * -javaagent:{jar包路徑}SizeOfObject.jar -XX:-UseCompressedOops * 不使用指針壓縮 * *Output: *amd64 *Object: 16 * *include one int: 24 *include two int: 24 *include three int: 32 * *include one object: 24 *include one object: 32 */ static void test2() { System.out.println(System.getProperty("os.arch")); System.out.printf("%-30s%9d ", "Object:", SizeOfObject.sizeOf(new Object())); System.out.println(); System.out.printf("%-30s%9d ", "include one int:", SizeOfObject.sizeOf(new IntegerTestOne())); System.out.printf("%-30s%9d ", "include two int:", SizeOfObject.sizeOf(new IntegerTestTwo())); System.out.printf("%-30s%9d ", "include three int:", SizeOfObject.sizeOf(new IntegerTestThree())); System.out.println(); System.out.printf("%-30s%9d ", "include one object:", SizeOfObject.sizeOf(new ReferenceTestOne())); System.out.printf("%-30s%9d ", "include one object:", SizeOfObject.sizeOf(new ReferenceTestTwo())); } public static void main(String[] args) { test2(); } static class IntegerTestOne { private int i1 = 1; } static class IntegerTestTwo { private int i1 = 1; private int i2 = 1; } static class IntegerTestThree { private int i1 = 1; private int i2 = 1; private int i3 = 1; } static class ReferenceTestOne { private Object o1 = new Object(); } static class ReferenceTestTwo { private Object o1 = new Object(); private Object o2 = new Object(); } }一些概念
對(duì)象內(nèi)存 = 對(duì)象頭 + 類型指針 + 對(duì)齊填充
對(duì)象頭不參與指針壓縮,并且 32 位時(shí)為 4 個(gè)字節(jié),64 位時(shí)為 8 個(gè)字節(jié)
類型指針參與指針壓縮,并且 32 位時(shí)為 4 個(gè)字節(jié),64 位時(shí)為 8 個(gè)字節(jié);指針壓縮時(shí) 64 位為 4 個(gè)字節(jié)
對(duì)齊填充,由于 jvm 設(shè)計(jì)內(nèi)存要為 8 字節(jié)的整數(shù)倍,所以不足的需要填充。如 對(duì)象頭和類型指針一共 12 字節(jié),填充后為 16 字節(jié),填充了 4 個(gè)字節(jié)
測(cè)試結(jié)果驗(yàn)證上面的假設(shè)其中 (8 + 8) 為對(duì)象頭和類型指針的字節(jié)數(shù)
64 位 | -XX:-UseCompressedOops | -XX:+UseCompressedOops |
---|---|---|
Object | 8 + 8 = 16 (對(duì)象頭+類型指針) | 8 + 4 + 4 = 16(對(duì)象頭+壓縮的類型指針+對(duì)齊填充) |
包含一個(gè)int | (8 + 8) + 4 + 4 = 24 | (8 + 4) + 4 = 16 |
包含兩個(gè)int | (8 + 8) + 4*2 = 24 | (8 + 4) + 4*2 + 4 = 24 |
包含三個(gè)int | (8 + 8) + 4*3 + 4 = 32 | (8 + 4) + 4*3 = 24 |
不壓縮引用占 8 個(gè)字節(jié),壓縮占 4 個(gè)字節(jié) | ||
包含一個(gè)引用 | (8 + 8) + 8 = 24 | (8 + 4) + 4 = 16 |
包含兩個(gè)引用 | (8 + 8) + 8*2 = 32 | (8 + 4) + 4*2 + 4 = 24 |
public class MemoryStaticTest { /** * -javaagent:{jar包路徑}SizeOfObject.jar * 使用指針壓縮,在一定情況下64位HotSpot jvm默認(rèn)指針壓縮 * * Output: * amd64 +UseCompressedOops * StaticTest: 16 * Integer: 16 * StaticReferenceTest: 16 * * @param args */ public static void main(String[] args) { System.out.println(System.getProperty("os.arch") + " +UseCompressedOops"); System.out.printf("%-30s%9d ", "StaticTest:", SizeOfObject.sizeOf(new StaticTest())); System.out.printf("%-30s%9d ", "Integer:", SizeOfObject.sizeOf(new Integer(1))); System.out.printf("%-30s%9d ", "StaticReferenceTest:", SizeOfObject.sizeOf(new StaticReferenceTest())); } static class StaticTest { private static int i1 = 1; private static int i2 = 1; private static int i3 = 1; private static int i4 = 1; private static int i5 = 1; private static int i6 = 1; } static class StaticReferenceTest { private static Object o1 = new Object(); private static Object o2 = new Object(); private static Object o3 = new Object(); private static Object o4 = new Object(); private static Object o5 = new Object(); } }
代碼中還有一點(diǎn)其他測(cè)試: https://github.com/Deeeeeeeee/jcoding.git
為什么是這個(gè)樣子呢對(duì)象頭在 64 位的時(shí)候,為什么是 8 個(gè)字節(jié);32 位的時(shí)候,為什么是 4 個(gè)字節(jié)
一個(gè)引用在 64 位的時(shí)候,為什么是 8 個(gè)字節(jié);32 位的時(shí)候,為什么是 4 個(gè)字節(jié)
這個(gè)跟 C++ 指針有關(guān)了,跟寄存器有關(guān)了
指針壓縮又是怎么個(gè)回事
參考鏈接這一切都可以在 jvm 的實(shí)現(xiàn)中找到答案,也就是看 C++ 代碼。只是我還沒到這個(gè)階段=。=
【Java對(duì)象解析】不得不了解的對(duì)象頭
JDK從6 update 23開始在64位系統(tǒng)上會(huì)默認(rèn)開啟壓縮指針
【Java JVM】 Hotspot GC研究- 64位引用指針壓縮技術(shù)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/70798.html
摘要:對(duì)于不同的實(shí)現(xiàn),對(duì)象占用的內(nèi)存空間大小可能不盡相同,本文主要分析中的情況,實(shí)驗(yàn)環(huán)境為位系統(tǒng),使用進(jìn)行結(jié)論驗(yàn)證。內(nèi)存占用這里分析一個(gè)只有一組鍵值對(duì)的結(jié)構(gòu)如下首先分析本身的大小。 本文深入分析并驗(yàn)證了不同Java對(duì)象占用內(nèi)存空間大小的情況。對(duì)于不同的jvm實(shí)現(xiàn),Java對(duì)象占用的內(nèi)存空間大小可能不盡相同,本文主要分析HotSpot jvm中的情況,實(shí)驗(yàn)環(huán)境為64位window10系統(tǒng)、JD...
摘要:堆內(nèi)存用于存放我們?cè)诔绦蛑袆?chuàng)建的對(duì)象,一旦沒有足夠的空間用于存放這些對(duì)象,即會(huì)拋出異常。當(dāng)我們采用后一種方式時(shí),我們需要了解一個(gè)對(duì)象是如何占據(jù)堆內(nèi)存空間的,或者說是了解一個(gè)對(duì)象是由哪些部分組成的。 JVM將內(nèi)存劃分為程序計(jì)數(shù)器(Program Counter Register)、虛擬機(jī)棧(VM Stack)、本地方法棧(Native Method Stack)、堆(Heap)以及方法區(qū)...
摘要:在一般應(yīng)用中,不會(huì)逃逸的局部對(duì)象所占的比例很大,如果能使用棧上分配,那大量的對(duì)象就會(huì)隨著方法的結(jié)束而自動(dòng)銷毀了,垃圾收集系統(tǒng)的壓力將會(huì)小很多。相關(guān)參數(shù)設(shè)置大對(duì)象直接進(jìn)入年老代的閾值,當(dāng)對(duì)象大小超過這個(gè)值時(shí),將直接在年老代分配。 jvm系列 垃圾回收基礎(chǔ) JVM的編譯策略 GC的三大基礎(chǔ)算法 GC的三大高級(jí)算法 GC策略的評(píng)價(jià)指標(biāo) JVM信息查看 GC通用日志解讀 jvm的card t...
摘要:本文詳細(xì)描述了堆內(nèi)存模型,垃圾回收算法以及處理內(nèi)存泄露的最佳方案,并輔之以圖表,希望能對(duì)理解內(nèi)存結(jié)構(gòu)有所幫助。該區(qū)域也稱為內(nèi)存模型的本地區(qū)。在中,內(nèi)存泄露是指對(duì)象已不再使用,但垃圾回收未能將他們視做不使用對(duì)象予以回收。 本文詳細(xì)描述了 Java 堆內(nèi)存模型,垃圾回收算法以及處理內(nèi)存泄露的最佳方案,并輔之以圖表,希望能對(duì)理解 Java 內(nèi)存結(jié)構(gòu)有所幫助。原文作者 Sumith Puri,...
摘要:作用默認(rèn),即,適當(dāng)調(diào)整年輕代大小,可以一定層度上較少出現(xiàn)的概率其余性能調(diào)優(yōu)常用參數(shù)設(shè)置指定的初始和最大堆內(nèi)存大小,兩值可以設(shè)置相同,以避免每次垃圾回收完成后重新分配內(nèi)存。 Java性能優(yōu)化之針對(duì)分代垃圾回收調(diào)整 [TOC] JVM內(nèi)存的系統(tǒng)級(jí)的調(diào)優(yōu)主要的目的是減少M(fèi)inor GC的頻率和Full GC的次數(shù),過多的Minor GC和Full GC是會(huì)占用很多的系統(tǒng)資源,影響系統(tǒng)的吞吐...
摘要:對(duì)字節(jié)碼文件進(jìn)行解釋執(zhí)行,把字節(jié)碼翻譯成相關(guān)平臺(tái)上的機(jī)器指令。使用命令可對(duì)字節(jié)碼文件以及配置文件進(jìn)行打包可對(duì)一個(gè)由多個(gè)字節(jié)碼文件和配置文件等資源文件構(gòu)成的項(xiàng)目進(jìn)行打包。和不存在永久代這種說法。 Java技術(shù)體系 從廣義上講,Clojure、JRuby、Groovy等運(yùn)行于Java虛擬機(jī)上的語(yǔ)言及其相關(guān)的程序都屬于Java技術(shù)體系中的一員。如果僅從傳統(tǒng)意義上來看,Sun官方所定義的Jav...
閱讀 2484·2023-04-25 19:24
閱讀 1700·2021-11-11 16:54
閱讀 2833·2021-11-08 13:19
閱讀 3547·2021-10-25 09:45
閱讀 2552·2021-09-13 10:24
閱讀 3276·2021-09-07 10:15
閱讀 4014·2021-09-07 10:14
閱讀 2950·2019-08-30 15:56