麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

對象

2019-11-15 00:00:32
字體:
來源:轉載
供稿:網友
對象

對象的創建(不包括數組和Class對象)

  虛擬機遇到一條new指令時,首相檢查這個指令的參數是否能再常量池中定位到一個類的符號引用,并且檢查這個符號引用代表的類是否已被加載、解析和初始化過。如果沒有,那必須先執行相應的類加載過程。

  類加載檢查通過后,虛擬機將為新生對象分配內存。對象所需的大小再類加載完成后便可完全確定(如何確定參見下一小節)。為對象分配內存的任務等同于把一塊確定大小的內存從java堆中劃分出來。有兩種情況:1.Java堆中內存時絕對規整的,所有使用中的內存在一邊,空閑內存在另一邊,中間有一個指針作為分界點的指示器,則分配內存就是將指針向空閑內存一邊挪動與對象大小相等的距離,這種分配方法成為“指針碰撞(Bump the Pointer)”。2.Java堆中內存并不是規整的,使用中和空閑的內存相互交錯,這時虛擬機必須維護一個用于記錄那些內存快可用的列表,在分配的時候從列表中找到一塊足夠大的空間劃分給對象,并更新列表上的記錄,這種方法稱為“空閑列表(Free List)”。選擇哪種分配方法取決于內存是否規整,內存是否規整又取決于垃圾收集器是否帶有壓縮整理功能。

  另一個需要考慮的問題是上述的內存分配過程并不是線程安全的,有兩種方法解決這個問題:1.對分配內存空間的動作進行同步處理——實際上虛擬機采用CAS配上失敗重試的方式保證更新操作的原子性。2.把內存分配的動作按照線程劃分在不同的空間中進行,即每個線程在Java堆中預先分配一小塊內存,稱為本地線程分配緩沖(Thread Local Allocation Buffer, TLAB)。哪個線程要分配內存就在哪個線程的TLAB上分配,只有TLAB用完并分配新的TLAB時,才需要同步鎖定。是否使用TLAB可以通過 -XX:+/-UseTLAB 參數來設定。

  內存分配完成后,虛擬機需要將分配的內存空間都初始化為零值,如果使用TLAB,該過程也可以提前到TLAB分配時進行。

  接下來,虛擬機要對對象進行必要到設置,例如這個對象時哪個類的實例、如何才能找到類的元數據信息、對象的哈希碼、對象的GC分代年齡等信息。這些信息存放在對象的對象頭(Object Header)中。

  最后,執行<init>方法,按程序員意愿對對象進行初始化,產生一個真正可用的對象。

  下面時HotSpot虛擬機bytecodeInterPReter.cpp中的代碼片段:

 1     // 確保常量池中存放的是已解釋的類 2     if (!constants->tag_at(index).is_unresolved_klass())  { 3         //斷言確定klassOop和instanceKlassOop 4         oop entry = (klassOop) *constants->obj_at_addr(index); 5         assert(entry->is_klass(), "Should be resolved klass"); 6         klassOop k_entry = (klassOop) entry; 7         assert(k_entry->klass_part()->oop_is_instance(), "Should be instanceKlass"); 8         instanceKlass* ik = (instanceKlass*) k_entry->klass_part(); 9         // 確保對象所屬類型已經經過初始化階段10         if (ik->is_initialized() && ik->can_be_fastpath_allocated()) {11             // 取對象長度12             size_t obj_size = ik->size_helper();13             oop result = NULL;14             bool need_zero = !zeroTLAB;15             if (UserTLAB) {16                 result = (oop) THREAD->tlab().allocate(obj_size);17             }18             if (result == NULL) {19                 need_zero = true;20                 // 直接在eden中分配對象21         retry:22                 HeapWord* compare_to = *Universe::heap()->top_addr();23                 HeapWord* new_top = compare_to + obj_size;24                 // cmpxchg 是x86中的CAS指令,這里是一個c++方法,通過CAS方式分配空間25                 // 如果并發失敗,轉到retry中重試,知道成功分配為止26                 if (new_top <= *Universe::heap()->end_addr()) {27                     if (Atomic::cmpxchg_ptr(new_top, Universe::heap()->top_addr(), compare_to) != compare_to) {28                         goto retry;29                     }30                     result = (oop) compare_to;31                 }32             }33             if (result != NULL) {34                 // 如果需要,則為對象初始化零值35                 if (need_zero) {36                     HeapWord* to_zero = (HeapWord*) result + sizeof(oopDesc) / oopSize;37                     obj_size -= sizeof(oopDesc) / oopSize;38                     if (obj_size > 0) {39                         memset(to_zero, 0, obj_size * HeapWordSize);40                     }41                 }42                 // 根據是否啟用偏向鎖來設置對象頭信息43                 if (UseBiasedLocking) {44                     result->set_mark(ik->prototype_header();45                 } else {46                     result->set_mark(markOopDesc::prototype());47                 }48                 result->set_klass_gap(0);49                 result->set_klass(k_entry);50                 // 將對象引用入棧,繼續執行下一條指令51                 SET_STACK_OBJECT(result, 0);52                 UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1);53             }54         }55     }

對象的內存布局

  在HotSpot虛擬機中,對象在內存中存儲的布局可以分為3塊區域:對象頭(Header)、實例數據(Instance Data)和對齊填充(Padding)。

  對象頭包括兩部分:

  1. 用于存儲對象自身的運行時數據,如哈希碼(HashCode)、GC分代年齡、鎖狀態標志、線程持有的鎖、偏向線程ID、偏向時間戳等,這部分數據長度在32位和64位虛擬機中分別為32bit和64bit,稱為“Mark Word”。需要存儲的運行時數據超過32位或64位Bitmap結果所能記錄的限度,Mark Word被設計成一個非固定的數據結構以便在極小的空間內存儲盡量多信息,它會根據對象的狀態服用自己的存儲空間。例如在32位的HotSpot虛擬機中對象未被鎖定的狀態下,Mark Word的32個bits空間中的25bits用于存儲對象哈希碼(HashCode),bits用于存儲對象分代年齡,2bits用于存儲鎖標志位,bit固定為0,在其他狀態(輕量級鎖定、重量級鎖定、GC標記、可偏向)下對象的存儲內容如下表所示。
    存儲內容標志位狀態
    對象哈希碼、對象分代年齡01未鎖定
    指向鎖記錄的指針00輕量級鎖定
    指向重量級鎖的指針10膨脹(重量級鎖定)
    空,不需要記錄信息11GC標記
    偏向線程ID、偏向時間戳、對象分代年齡01可偏向
  2. 類型指針,即對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。

  實例數據部分是對象真正存儲的有效信息,也是在程序代碼中所定義的各種類型的字段內容。包括父類繼承的和子類定義的都需要記錄下來。這部分存儲順序會受虛擬機分配策略參數和字段在Java源碼中定義順序的影響。HotSpot虛擬機默認的分配策略為longs/doubles、ints、shorts/chars、bytes/booleans、oops(Ordinary Object Pointers),從分配策略中可以看出,相同寬度的字段總是被分配到一起。在滿足這個前提條件的情況下,在父類中定義的變量會出現在子類之前。如果CompactFields參數值為true(默認為true),那子類之中較窄的變量也可能會插入到父類變量的空隙之中。

  對齊填充并不是必然存在,沒有特別含義,僅僅起占位符的作用。對象的大小必須是8字節的整數倍。

對象的訪問定位

  我們的Java程序需要通過棧上的reference數據來操作堆上的具體對象,目前主流的訪問方式有使用句柄和直接指針兩種:

  • 使用句柄訪問,Java堆中會劃分出一塊內存來作為句柄池,reference中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據與類型數據的具體各自的地址信息,如下圖
  • 直接指針訪問,Java堆對象的布局中就必須考慮如何放置訪問類型數據的相關信息,reference中存儲的直接就是對象地址,如下圖

  使用句柄來訪問的最大好處就是reference中存儲的是穩定句柄地址,在對象被移動(垃圾收集時移動對象是非常普遍的行為)時只會改變句柄中的實例數據指針,而reference本身不需要被修改。使用直接指針來訪問最大的好處就是速度更快,它節省了一次指針定位的時間開銷,由于對象訪問的在Java中非常頻繁,因此這類開銷積小成多也是一項非常可觀的執行成本。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 黄色视屏免费看 | 欧美一区二区三区中文字幕 | 色综av| 偷偷草网站 | 最新福利在线 | 欧美成年性h版影视中文字幕 | 鲁丝一区二区二区四区 | 久久免费视频一区二区三区 | 国产成人精品网站 | www.成人在线视频 | xnxx 日本19 | 国产精品免费久久久 | 丰满年轻岳中文字幕一区二区 | 久久久婷婷 | 一区二区三高清 | 国产精品久久久久久久午夜片 | 毛片视频观看 | 国产一级一片免费播放 | 校花被肉干高h潮不断 | 亚洲综合精品 | 免费在线观看亚洲 | 一级免费毛片 | 久久精品国产亚洲7777小说 | 国产亚洲精品久久久久久久软件 | 91福利在线观看 | 视频一区二区精品 | 九一免费国产 | 精品一区二区三区免费毛片爱 | 国产不卡av在线 | 一级毛片在线观看免费 | 国产自在自线午夜精品视频在 | 成人综合一区二区 | 伊人午夜 | 亚洲aⅴ免费在线观看 | 日韩一级电影在线观看 | 男女做性免费网站 | 日韩av有码在线 | 日韩精品中文字幕在线播放 | 国产欧美一区二区三区免费看 | 成人羞羞视频在线观看 | 国产一区在线视频观看 |