国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

聊聊Java對象在內(nèi)存中的大小

tianren124 / 3201人閱讀

摘要:聊聊對象在內(nèi)存中的大小本文討論的對象在內(nèi)存中的大小指的是在堆中的大小未特殊說明,提到的地方都指的是,版本。而實際是運行方法會看到結(jié)果對象實例總大小,空間損失。數(shù)組也是對象,但數(shù)組的中包含有一個類型的值,又多占了的空間,所以數(shù)組的大小是。

聊聊Java對象在內(nèi)存中的大小

本文討論的Java對象在內(nèi)存中的大小指的是在堆(Heap)中的大小;未特殊說明,提到JVM的地方都指的是:Java HotSpot(TM) 64-Bit Server VM,版本:1.8.0_131

Java中Object的組成:

Object = Header + Primitive Fields + Reference Fields + Alignment & Padding`

Header由兩部分組成:標(biāo)記部分(Mark Word)和原始對象引用(Klass Pointer/Object Original Pointer)- mark word & klass pointer。

標(biāo)記部分的大小是一個word size(64-bit JVM上是8 bytes,32-bit JVM上是4 bytes),包括了該對象的identity hash code和一些標(biāo)記(比如鎖和年代信息)。

原始對象引用在32-bit JVM上的大小是4 bytes,在64-bit JVM上可以是4 bytes,也可以是8 bytes,由JVM參數(shù)“是否壓縮原始對象”決定,在HotSpot中是UseCompressedOops參數(shù)(jdk1.8 和jdk1.9默認(rèn)是開啟的)。

Primitive Fields && Reference Fields

類型 大小
Object Reference word size
byte 1 byte
boolean 1 byte
char 2 bytes
short 2 bytes
int 4 bytes
float 4 bytes
double 8 bytes
long 8 bytes

對齊(Alignment)和補齊(Padding)

對齊,任何對象都是以8 bytes的粒度來對齊的

怎么理解這句話呢?請看一個例子,new Object()產(chǎn)生的對象的大小是多少呢?12 bytes的header,但對齊必須是8的倍數(shù),還有4 bytes的alignment,所以對象的大小是16 bytes.

補齊,補齊的粒度是4 bytes

可以簡單理解為,JVM分配內(nèi)存空間一次最少分配8 bytes,對象中字段對齊的最小粒度為4 bytes

準(zhǔn)備工作

本文使用Maven管理Jar包,源碼在這里。

pom.xml中引入JOL(Java Object Layout, 使用實例 )依賴,用于展示對象在Heap中的分布(layout):


    org.openjdk.jol
    jol-core
    0.9

第一個測試:

public static void main(String[] args) {
    System.out.println(VM.current().details());
}

執(zhí)行后,會輸出:

# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
# Objects are 8 bytes aligned.  // 以 8 bytes的粒度對齊
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]    // 分別對應(yīng)[Oop(Object Original Pointer), boolean, byte, char, short, int, float, long, double]的大小
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]    // 數(shù)組中元素的大小,分別對應(yīng)的是[Oop(Object Original Pointer), boolean, byte, char, short, int, float, long, double]

對象在Heap中的分布遵循的規(guī)則:

重排序, JVM在Heap中給對象布局時,會對field進(jìn)行重排序,以節(jié)省空間。

例-1,對于類:

public class Reorder {

    private byte a;

    private int b;

    private boolean c;
    
    private float d;

    private Object e;
    
    public static void main(String[] args) {
        System.out.println(ClassLayout.parseClass(Reorder.class).toPrintable());
    }
}

如果沒有重排序,對象的分布會是這個樣子的:

objectsize.Reorder object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0    12           (object header)                           N/A
     12     1      byte Reorder.a                                 N/A
     13     3           (alignment/padding gap)                  
     16     4       int Reorder.b                                 N/A
     20     1   boolean Reorder.c                                 N/A
     21     3           (alignment/padding gap)                  
     24     4     float Reorder.d                                 N/A
     28     2      char Reorder.e                                 N/A
     30     2           (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 6 bytes internal + 2 bytes external = 8 bytes total

對象實例總大小:32 bytes,空間損失:8 bytes。

而實際是(運行main方法會看到結(jié)果):

objectsize.Reorder object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0    12           (object header)                           N/A
     12     4       int Reorder.b                                 N/A
     16     4     float Reorder.d                                 N/A
     20     2      char Reorder.e                                 N/A
     22     1      byte Reorder.a                                 N/A
     23     1   boolean Reorder.c                                 N/A
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

對象實例總大小:24 bytes,空間損失:0 bytes。

為了避免空間浪費,一般情況下,field分配的優(yōu)先依次順序是:double > long > int > float > char > short > byte > boolean > object reference
注意到了沒,這里有個基本的原則是:盡可能先分配占用空間大的類型(除了object reference)。這里的盡可能有兩層含義:

在同等優(yōu)先級情況下,按這個順序分配。 例-2

public class Order {
    
    private int ignoreMeTentatively;
    
    private byte a;
    
    private boolean b;
    
    private char c;
    
    private short d;
    
    private int e;
    
    private float f;
    
    private double g;
    
    private long h;
    
    private Object i;
    
    public static void main(String[] args) {
        System.out.println(ClassLayout.parseClass(Order.class).toPrintable());
    }
}

這個類的實例在內(nèi)存中分布是:

objectsize.Reorder object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0    12           (object header)                           N/A
     12     4       int Reorder.b                                 N/A
     16     4     float Reorder.d                                 N/A
     20     2      char Reorder.e                                 N/A
     22     1      byte Reorder.a                                 N/A
     23     1   boolean Reorder.c                                 N/A
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

請先忽略ignoreMeTentatively字段,可以驗證類型分配的順序。

在考慮到補齊(Padding)的情況下,排在后面的類型有可能比排在前面的優(yōu)先級更高。

回過頭來看例-1例-2,會發(fā)現(xiàn)header后的字一個field(offset 12)都是int類型的。為什么呢?
這就是AlignmentPadding共同作用的結(jié)果。

JVM每次最少分配8 bytes的空間,而header的大小是12。
也就是說,已經(jīng)分配了16 bytes的空間了,如果嚴(yán)格按照前面說的那個順序,最先分配一個double類型的field,就需要在這之前先分配4 bytes的空間來補齊,也就這4 bytes的空間就白白浪費了。
這中情況下,<=Padding Size(4 bytes)的類型的優(yōu)先級就高于大小>Padding Size的類型了。
而在所有大小<=Padding Size的類型中,int的優(yōu)先級又是最高的,所以header后的第一個field是int

為了進(jìn)一步理解,再來看個例子,例-3

public class Padding {
      
    private char a;
      
    private boolean b;
      
    private long c;
      
    private Object d;
  
    public static void main(String[] args) {
          System.out.println(ClassLayout.parseClass(Padding.class).toPrintable());
   }
}

這個類的實例在內(nèi)存中分布是:

objectsize.Padding object internals:
 OFFSET  SIZE               TYPE DESCRIPTION                               VALUE
      0    12                    (object header)                           N/A
     12     2               char Padding.a                                 N/A
     14     1            boolean Padding.b                                 N/A
     15     1                    (alignment/padding gap)                  
     16     8               long Padding.c                                 N/A
     24     4   java.lang.Object Padding.d                                 N/A
     28     4                    (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 1 bytes internal + 4 bytes external = 5 bytes total

可以看到header后的4個bytes空間分配情況,在所有大小<=Padding Size的類型中,char的優(yōu)先級最高,其次是boolean
這兩個加起來只有3 bytes( 接下來,JVM再分配一個8 bytes大小的空間,很明顯空間足夠的情況下,long的優(yōu)先級最高,也正好用完這8 bytes的空間。
然后,JVM繼續(xù)分配一個8 bytes大小的空間,最后一個類型object reference(這里是Object)了,在開啟UseCompressedOops的情況下,使用4 bytes的空間,還有4 bytes的空間只能用來對齊了。

子類和父類的field永遠(yuǎn)不會混合在一起,并且父類的field分配完之后才會給子類的field分配空間。

例-4

public class SuperA {
    
    long a;
    
    private int b;
    
    private float c;
        
    private char d;
        
    private short e;
}

public class SubA extends SuperA {
    
    private long d;

    public static void main(String[] args) {
        System.out.println(ClassLayout.parseClass(SubA.class).toPrintable());
    }
    
}

SubA的實例在內(nèi)存中的分布是:

objectsize.SubA object internals:
   OFFSET  SIZE    TYPE DESCRIPTION                               VALUE
        0    12         (object header)                           N/A
       12     4     int SuperA.b                                  N/A
       16     8    long SuperA.a                                  N/A
       24     4   float SuperA.c                                  N/A
       28     2    char SuperA.d                                  N/A
       30     2   short SuperA.e                                  N/A
       32     8    long SubA.d                                    N/A
Instance size: 40 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

父類SuperA中的field全部分配完后,才分配子類SubAfield

父類的的最后一個字段與子類的第一個字段以一個Padding Size(4 bytes)來對齊。

例-5

public class SuperB {
    
    private byte a;
    
    private int b;

}

public class SubB extends SuperB {
    
    private int a;
    
    private long b;

    public static void main(String[] args) {
        System.out.println(ClassLayout.parseClass(SubB.class).toPrintable());
    }
}

SubB的實例在內(nèi)存中分布是:

objectsize.SubB object internals:
  OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
       0    12        (object header)                           N/A
      12     4    int SuperB.b                                  N/A
      16     1   byte SuperB.a                                  N/A
      17     3        (alignment/padding gap)                  
      20     4    int SubB.a                                    N/A
      24     8   long SubB.b                                    N/A
Instance size: 32 bytes
Space losses: 3 bytes internal + 0 bytes external = 3 bytes total

從offset 16的位置開始看,父類還有最后一個字段a未分配,這時JVM分配一個8 bytes的空間,a占用1 byte,
還有7 bytes未使用,而這7 bytes空間沒有全部用于對齊,也就是說子類字段的分配并不是從offset 24 開始的。
實際上只用了3 bytes空間來對齊(湊夠4 bytes的Padding Size),剩下的4 bytes分配給了子類的a字段。

數(shù)組也是對象,但數(shù)組的header中包含有一個int類型的length值,又多占了4 bytes的空間,所以數(shù)組的header大小是16 bytes。

例-6

public class ArrayTest {
    public static void main(String[] args) {
        System.out.println(ClassLayout.parseInstance(new boolean[1]).toPrintable());
    }
}        

長度為1的boolean數(shù)組的實例在內(nèi)存的分布是:

[Z 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)                           05 00 00 f8 (00000101 00000000 00000000 11111000) (-134217723)
   12     4           (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
   16     1   boolean [Z.                             N/A
   17     7           (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 7 bytes external = 7 bytes total

可以看到,header占用了16 bytes,一個boolean元素占用了1 bytes,剩余7 bytes用于對齊。

參考資料

java-object-memory-structure/

java-object-memory-layout

what-is-the-memory-consumption-of-an-object-in-java)

openjdk-java object layout

java object layout examples

Java Object Size Calculations in 64-bit

mark word & klass pointer

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/70761.html

相關(guān)文章

  • 聊聊企業(yè)級 Java 應(yīng)用最重要的4個性能指標(biāo)

    摘要:筆者多次參與銀行運營商等大型企業(yè)的性能優(yōu)化工作總結(jié)了企業(yè)級應(yīng)用最應(yīng)重視的個性能指標(biāo),主要包括商業(yè)事務(wù),外部服務(wù),垃圾回收以及應(yīng)用布局。應(yīng)用布局最后要探討的性能指標(biāo)是應(yīng)用布局。另一個需要監(jiān)測的是容器性能。 雖然很多人都曾預(yù)言 Java 將一蹶不振,但是不可否認(rèn)的是,很多重要項目中,尤其是銀行和政府一些大型項目,Java 仍在其中扮演著極其重要的角色。筆者多次參與銀行、運營商等大型企業(yè)的性...

    sherlock221 評論0 收藏0
  • 聊聊GC

    摘要:復(fù)制這一工作所花費的時間,在對象存活率達(dá)到一定程度時,將會變的不可忽視。針對老年代老年代的特點是區(qū)域較大,對像存活率高。這種情況,存在大量存活率高的對像,復(fù)制算法明顯變得不合適。 GC(Garbage Collection)即Java垃圾回收機制,是Java與C++的主要區(qū)別之一,作為Java開發(fā)者,一般不需要專門編寫內(nèi)存回收和垃圾清理代碼,對內(nèi)存泄露和溢出的問題,也不需要像C++程序...

    developerworks 評論0 收藏0
  • 深入理解Java虛擬機(自動內(nèi)存管理機制)

    摘要:看來還是功力不夠,索性拆成了六篇文章,分別從自動內(nèi)存管理機制類文件結(jié)構(gòu)類加載機制字節(jié)碼執(zhí)行引擎程序編譯與代碼優(yōu)化高效并發(fā)六個方面來做更加細(xì)致的介紹。本文先說說虛擬機的自動內(nèi)存管理機制。在類加載檢查通過后,虛擬機將為新生對象分配內(nèi)存。 歡迎關(guān)注微信公眾號:BaronTalk,獲取更多精彩好文! 書籍真的是常讀常新,古人說「書讀百遍其義自見」還是蠻有道理的。周志明老師的這本《深入理解 Ja...

    yck 評論0 收藏0
  • 面試官問我JVM調(diào)優(yōu),我忍不住了!

    面試官:今天要不來聊聊JVM調(diào)優(yōu)相關(guān)的吧?面試官:你曾經(jīng)在生產(chǎn)環(huán)境下有過調(diào)優(yōu)JVM的經(jīng)歷嗎?候選者:沒有面試官:...候選者:嗯...是這樣的,我們一般優(yōu)化系統(tǒng)的思路是這樣的候選者:1. 一般來說關(guān)系型數(shù)據(jù)庫是先到瓶頸,首先排查是否為數(shù)據(jù)庫的問題候選者:(這個過程中就需要評估自己建的索引是否合理、是否需要引入分布式緩存、是否需要分庫分表等等)候選者:2. 然后,我們會考慮是否需要擴(kuò)容(橫向和縱向都...

    不知名網(wǎng)友 評論0 收藏0
  • Java 桌面軟件開發(fā)到底如何?就本人的經(jīng)驗聊聊

    摘要:桌面軟件開發(fā)一直以來是程序員不敢輕易涉足的地方,原因有三丑慢難。打包還有一個人們關(guān)心的方面就是軟件如何打包。這是如今很多軟件的做法。但說到底桌面開發(fā)本身究竟如何我已經(jīng)用做了將近兩年的開發(fā),我覺得已經(jīng)可以滿足桌面開發(fā)的基本需要。 Java FX 桌面軟件開發(fā)一直以來是 Java 程序員不敢輕易涉足的地方,原因有三:丑、慢、難。而自從 Java 8.0 將 JavaFX 包含進(jìn)來之后,情況...

    Jeff 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<