JAVA 對象到底有什么


我們用Java來編寫程序,經常創建對象,那么Java中的對象到底包含什么東西呢?
 
JAVA 對象包括:
        1 對象頭
        2 對象的實例數據
        3 對齊填充
 
對象頭里面都有什么呢?
 
一、看看openjdk官方文檔怎么說的地址: http://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html
 
二、文檔對於object header的描述
   Common structure at the beginning of every GC-managed heap object. (Every oop points to an object header.) Includes fundamental information about the heap object's layout, type, GC state, synchronization state, and identity hash code. Consists of two words. In arrays it is immediately followed by a length field. Note that both Java objects and VM-internal objects have a common object header format.
 
翻譯過來
       每一個GC管理的堆對象的普通架構,(每一個oop指針指向的對象頭)包括堆對象的布局的基本信息,類型,GC狀態,syn鎖狀態和hash code,由2個words組成,如果是數組則會跟着數組的長度字段,java對象和VM內部對象有着相同的頭格式。
三、那么其中的2words是什么呢?一個word為:- mark word
  The first word of every object header. Usually a set of bitfields including synchronization state and identity hash code. May also be a pointer (with characteristic low bit encoding) to synchronization related information. During GC, may contain GC state bits.
 
翻譯過來
        每個對象頭的第一個word通常是一些列的 位字段,包括 鎖狀態、hash code,也可能是指向 synchronization相關的信息的指針,在GC過程中,也會包含GC狀態位
 
四、第二個word為- klass pointer
  The second word of every object header. Points to another object (a metaobject) which describes the layout and behavior of the original object. For Java objects, the "klass" contains a C++ style "vtable".
 
翻譯過來:
        每個對象的第二個word為一個指針,指向對象關聯的類信息
 
五、對象頭的具體組成結構 ,從源碼中獲取 - >openjdk\src\hotspot\share\oops\markWord.hpp - 64位機器組成結構
 
//  64 bits:
//  --------
//  unused:25(未使用25位) hash:31(hashcode占用31位) -->| unused_gap:1(未使用)   age:4(分代年齡占4位,最大值為15因此分代年齡最大為15)   biased_lock:1(偏向鎖1位) lock:2(鎖占2位) (normal object)   -- 普通的對象
//  JavaThread*:54 epoch:2 unused_gap:1   age:4    biased_lock:1 lock:2 (biased object)   -- 帶有鎖的對象
 
我們的計算機是小端存儲則打印出來的數據信息順序為:小端存儲( 低字節在前 高字節在后)  ,大端存儲(高字節在前 小字節在后)
 
六、打印對象頭信息 
  1)代碼中引入工具類
    
<dependency>
  <groupId>org.openjdk.jol</groupId>
  <artifactId>jol-core</artifactId>
  <version>0.9</version>
</dependency>

 

2)打印類信息
   測試類 
package com.test;
public class B {
}

 

import org.openjdk.jol.info.ClassLayout;
/**
* Hello world!
*-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode  -XX:-UseCompressedOops
*/
public class Test3
{
    static B b = new B();
    public static void main( String[] args )   {
        System.out.println(ClassLayout.parseInstance(b).toPrintable());
//        System.out.println( Integer.toHexString( b.hashCode()) );
//        System.out.println(VM.current().details());
//        System.out.println(ClassLayout.parseClass(B.class).toPrintable());
//        System.out.println(ClassLayout.parseInstance(b).toPrintable());
    }
}
View Code

 

 3)打印的結果
 
com.test.B 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)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4        (loss due to the next object alignment)
 
4)結果分析
  •    最后打印的頭信息為12個字節,理論上應該有16個字節(因為jvm開啟了指針壓縮的原因,可以加上參數去掉指針壓縮來查看-XX:-UseCompressedOops )
  •     最后的4個字節不是頭信息-是字節填充信息 - 對象儲存必須是8字節的倍數,不滿足則自動填充

六、對象頭-驗證hash存儲 - 打印的hash值是頭中的 2-5字節,並且顯示是反方向(小端存儲)

 

 

  2) 低端存儲展示(數據要反過來才能看明白), 分年年齡 、是否偏向 、鎖標識 位置

 

七、鎖標識驗證
     無鎖不可偏向001    - 對象打印了對象的hash,則前56位存儲了對象的hash,不能存儲鎖對應的線程id
     偏向鎖已偏向(101) -  前56位存儲了鎖線程的id,標識位顯示偏向鎖
     輕量級鎖(00),         - 前56位存儲了鎖線程的地址,標識位標識為 輕量級鎖
     重量級鎖(10), GC(11) -  前56位存儲了鎖線程的地址,標識位標識為 重量級的鎖
  •     當一把鎖第一次被線程持有的時候是偏向鎖,如果這個線程再次加鎖還是偏向鎖
  •     如果另一個線程也來加鎖(交替執行),膨脹為輕量鎖
  •     如果另一個線程在等待第一個線程釋放鎖(鎖競爭),則重量級鎖
八、代碼展示鎖標識變化 
   1)演示輕量級鎖
   
package com.test;//package com.test;


import org.openjdk.jol.info.ClassLayout;
/**
* Hello world!
*-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode  -XX:-UseCompressedOops
* -Xms1g -Xmx1g  -XX:+PrintGCDetails
*/
public class Test3
{
//    static B b = new B();
    public static void main( String[] args ) throws InterruptedException {
        B b = new B();
//        b.hashCode();
//        System.out.println(ClassLayout.parseInstance(b).toPrintable());
//        System.out.println( Integer.toHexString( b.hashCode()) );
//        synchronized (b){
//            System.out.println(ClassLayout.parseInstance(b).toPrintable());
//        }
        Test test1 = new Test(b);
        Thread t1 = new Thread(test1);
//        Test test2 = new Test(b);
//        Thread t2  = new Thread(test2);
        t1.start();
//        t1.join();
//        t2.start();
//        System.out.println(ClassLayout.parseInstance(b).toPrintable());
//        System.out.println(VM.current().details());
//        System.out.println(ClassLayout.parseClass(B.class).toPrintable());
    }
    public static class Test implements Runnable{
        private B b ;
        public Test(B b) {
            this.b = b;
        }
        @Override
        public void run() {
            synchronized (b){
                System.out.println(ClassLayout.parseInstance(b).toPrintable());
            }
        }
    }
}
View Code

 

 

2)演示重量級鎖,上面代碼加上:

  Test test2 = new Test(b);
        Thread t2  = new Thread(test2);
        t2.start();

  

 
 3)演示偏向鎖,需要加上下面“關閉偏向鎖延遲”
 
  • JVM參數修改
  //關閉延遲開啟偏向鎖
  -XX:BiasedLockingStartupDelay=0
  //禁止偏向鎖
  -XX:-UseBiasedLocking
  //啟用偏向鎖
  -XX:+UseBiasedLocking
  •   線程代碼修改,在對象加鎖前,加鎖時,加鎖后分別打印頭信息,觀察頭信息變化,代碼為:
public void run() {
 //加鎖前
    System.out.println(ClassLayout.parseInstance(b).toPrintable());
    synchronized (b){
        System.out.println(ClassLayout.parseInstance(b).toPrintable());
    }
//加鎖后
    System.out.println(ClassLayout.parseInstance(b).toPrintable());
}

 

 
  •      對象頭變化   
  •  

     

九、官方地址:

  openjdk  源碼: https://github.com/openjdk/jdk.git
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM