摘要:一個對象內存有多大為什么想知道這個,自以為很重要,其實。參考鏈接對象解析不得不了解的對象頭從開始在位系統上會默認開啟壓縮指針研究位引用指針壓縮技術
java 一個對象內存有多大
jdk: java 官網上下載的,HotSpot 虛擬機
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 參考的是 一個對象占用多少字節?
確認編譯時是 32 位還是 64 位,對測試結果有影響。x86 為 32 位, amd64 為 64 位,其余我不知道
System.out.println(System.getProperty("os.arch"));準備工作
SizeOfObject.java 直接從上面鏈接上拷貝
編譯這個類,得到 .class 文件
在包名路徑下執行一下命令進行打包(注意修改相應的包名):
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 屬性,添加上去即可
在運行測試程序的時候,添加 vm 參數
-javaagent:{jar包路徑}SizeOfObject.jar測試用例
測試 int, Object, 引用的大小。其余類型測試都類似
public class MemoryTest { /** * -javaagent:{jar包路徑}SizeOfObject.jar -XX:+UseCompressedOops * 使用指針壓縮,在一定情況下64位HotSpot jvm默認指針壓縮 * *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(); } }一些概念
對象內存 = 對象頭 + 類型指針 + 對齊填充
對象頭不參與指針壓縮,并且 32 位時為 4 個字節,64 位時為 8 個字節
類型指針參與指針壓縮,并且 32 位時為 4 個字節,64 位時為 8 個字節;指針壓縮時 64 位為 4 個字節
對齊填充,由于 jvm 設計內存要為 8 字節的整數倍,所以不足的需要填充。如 對象頭和類型指針一共 12 字節,填充后為 16 字節,填充了 4 個字節
測試結果驗證上面的假設其中 (8 + 8) 為對象頭和類型指針的字節數
64 位 | -XX:-UseCompressedOops | -XX:+UseCompressedOops |
---|---|---|
Object | 8 + 8 = 16 (對象頭+類型指針) | 8 + 4 + 4 = 16(對象頭+壓縮的類型指針+對齊填充) |
包含一個int | (8 + 8) + 4 + 4 = 24 | (8 + 4) + 4 = 16 |
包含兩個int | (8 + 8) + 4*2 = 24 | (8 + 4) + 4*2 + 4 = 24 |
包含三個int | (8 + 8) + 4*3 + 4 = 32 | (8 + 4) + 4*3 = 24 |
不壓縮引用占 8 個字節,壓縮占 4 個字節 | ||
包含一個引用 | (8 + 8) + 8 = 24 | (8 + 4) + 4 = 16 |
包含兩個引用 | (8 + 8) + 8*2 = 32 | (8 + 4) + 4*2 + 4 = 24 |
public class MemoryStaticTest { /** * -javaagent:{jar包路徑}SizeOfObject.jar * 使用指針壓縮,在一定情況下64位HotSpot jvm默認指針壓縮 * * 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(); } }
代碼中還有一點其他測試: https://github.com/Deeeeeeeee/jcoding.git
為什么是這個樣子呢對象頭在 64 位的時候,為什么是 8 個字節;32 位的時候,為什么是 4 個字節
一個引用在 64 位的時候,為什么是 8 個字節;32 位的時候,為什么是 4 個字節
這個跟 C++ 指針有關了,跟寄存器有關了
指針壓縮又是怎么個回事
參考鏈接這一切都可以在 jvm 的實現中找到答案,也就是看 C++ 代碼。只是我還沒到這個階段=。=
【Java對象解析】不得不了解的對象頭
JDK從6 update 23開始在64位系統上會默認開啟壓縮指針
【Java JVM】 Hotspot GC研究- 64位引用指針壓縮技術
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/70798.html
摘要:對于不同的實現,對象占用的內存空間大小可能不盡相同,本文主要分析中的情況,實驗環境為位系統,使用進行結論驗證。內存占用這里分析一個只有一組鍵值對的結構如下首先分析本身的大小。 本文深入分析并驗證了不同Java對象占用內存空間大小的情況。對于不同的jvm實現,Java對象占用的內存空間大小可能不盡相同,本文主要分析HotSpot jvm中的情況,實驗環境為64位window10系統、JD...
摘要:堆內存用于存放我們在程序中創建的對象,一旦沒有足夠的空間用于存放這些對象,即會拋出異常。當我們采用后一種方式時,我們需要了解一個對象是如何占據堆內存空間的,或者說是了解一個對象是由哪些部分組成的。 JVM將內存劃分為程序計數器(Program Counter Register)、虛擬機棧(VM Stack)、本地方法棧(Native Method Stack)、堆(Heap)以及方法區...
摘要:在一般應用中,不會逃逸的局部對象所占的比例很大,如果能使用棧上分配,那大量的對象就會隨著方法的結束而自動銷毀了,垃圾收集系統的壓力將會小很多。相關參數設置大對象直接進入年老代的閾值,當對象大小超過這個值時,將直接在年老代分配。 jvm系列 垃圾回收基礎 JVM的編譯策略 GC的三大基礎算法 GC的三大高級算法 GC策略的評價指標 JVM信息查看 GC通用日志解讀 jvm的card t...
摘要:本文詳細描述了堆內存模型,垃圾回收算法以及處理內存泄露的最佳方案,并輔之以圖表,希望能對理解內存結構有所幫助。該區域也稱為內存模型的本地區。在中,內存泄露是指對象已不再使用,但垃圾回收未能將他們視做不使用對象予以回收。 本文詳細描述了 Java 堆內存模型,垃圾回收算法以及處理內存泄露的最佳方案,并輔之以圖表,希望能對理解 Java 內存結構有所幫助。原文作者 Sumith Puri,...
摘要:作用默認,即,適當調整年輕代大小,可以一定層度上較少出現的概率其余性能調優常用參數設置指定的初始和最大堆內存大小,兩值可以設置相同,以避免每次垃圾回收完成后重新分配內存。 Java性能優化之針對分代垃圾回收調整 [TOC] JVM內存的系統級的調優主要的目的是減少Minor GC的頻率和Full GC的次數,過多的Minor GC和Full GC是會占用很多的系統資源,影響系統的吞吐...
摘要:對字節碼文件進行解釋執行,把字節碼翻譯成相關平臺上的機器指令。使用命令可對字節碼文件以及配置文件進行打包可對一個由多個字節碼文件和配置文件等資源文件構成的項目進行打包。和不存在永久代這種說法。 Java技術體系 從廣義上講,Clojure、JRuby、Groovy等運行于Java虛擬機上的語言及其相關的程序都屬于Java技術體系中的一員。如果僅從傳統意義上來看,Sun官方所定義的Jav...
閱讀 2490·2023-04-25 19:24
閱讀 1710·2021-11-11 16:54
閱讀 2840·2021-11-08 13:19
閱讀 3554·2021-10-25 09:45
閱讀 2561·2021-09-13 10:24
閱讀 3290·2021-09-07 10:15
閱讀 4038·2021-09-07 10:14
閱讀 2959·2019-08-30 15:56