## 對象的創建
java是一門面向對象的語言。在Java程序執行過程中無時無刻有Java對象被創建出來。在語言層面上,創建對象(克隆、反序列化)一般是一個newkeyword而已,而在虛擬機中,對象的創建步驟例如以下:
* 1、當虛擬機遇到new指令時。首先將去檢查這個指令參數能否在常量池中定位到一個類的引用符號,而且檢查這個符號引用代表的類是否被載入、解析和初始化過。假設沒有。那必須先執行相應的類載入過程。
* 2、在類載入檢查通過以后。接下來虛擬機將為新生對象分配內存。對象所需的內存大小在類載入后便確定。為對象分配空間的任務等同于把一塊確定大小的內存從Java堆劃分出來。
假設Java堆中的內存并非規整的,已使用的內存和空暇內存相互交錯,那就沒辦法簡單的進行指針碰撞了,虛擬機就必須維護一個隊列表,記錄哪些內存塊是可用的,在分配的時候從列表中找到一塊足夠大的空間劃分給對象實例,并更新列表上的記錄,這樣的分配方式稱為:“空暇列表”。選擇哪種分配方式由Java堆是否規則決定。
除了怎樣劃分可用空間之外。還有另外一個須要考慮的問題是對象創建在虛擬機中是很頻繁的行為,即使是僅僅改動一個指針所指向的位置,在并發情況下也并非線程安全的。可能出現正在給對象A分配內存,指針還沒來得及改動,對象B又同一時候使用了原來的指針來分配內存的情況。解決這一問題的方案是:
2.1對分配內存空間的動作進行同步處理——實際上虛擬機採用CAS配上失敗重試的方式,保證更新操作原子性
把內存分配的動作依照線程劃分在不同空間之中進行。即每一個線程在Java堆中預先分配一小塊內存。稱為本地線程分配緩存(TLAB)。哪個線程要分配內存,就在哪個線程的TLAB上分配,僅僅有TLAB用完并分配新的TLAB時,才須要同步鎖定。虛擬機是否使用TLAB,能夠通過-XX:+/-UseTLAB參數來設定。
* 3、內存分配完畢以后。虛擬機須要將分配到的內存空間都初始化為零值(不包括對象頭),假設使用TLAB,這一工作過程也能夠提前至TLAB分配時進行,這一步操作保證了對象實例字段在Java代碼中能夠不賦初始值就能直接使用,程序能訪問到這些字段的數據類型所相應的零值。
* 4、接下來虛擬機要對對象進行必要的設置,比如:這個對象是哪個類的實例、怎樣才干找到類的元數據信息、對象的哈希碼、對象GC分代年齡信息等。這些信息存放在對象的信息頭之中。依據虛擬機執行狀態的不同。如是否使用偏向鎖等,對象頭會有不同的設置方式。
上述工作完畢以后,從虛擬機角度來看,一個新的對象已經產生了,可是從Java程序來看,對象才剛剛開始——(init)方法還沒有執行。全部的字段都還為零,所以,一般來說。執行new命令后。會接著執行init方法。把對象依照程序猿的意愿進行初始化,這樣一個真正可用的對象才算全然產生出來。
## 對象的內存布局
還Hotspot虛擬機中,對象的內存中存儲的布局分為3塊區域:對象頭(header)、實例數據(Instance Data)、對其填充(Padding)
Hotspot虛擬機的對象頭包括兩部分信息,第一部分用于存儲自身執行時的數據,比如:哈希碼、GC分代年齡、鎖狀態標識、線程持有鎖、偏向線程id、偏向時間戳,這部分數據數據長度在32位和64位的虛擬機(未開啟指針壓縮)中分別為32bit和64bit,官方稱為’Mark word’。
對象須要存儲的執行時的數據許多。已經超出了32位、64位bitmap結構所能記錄的限度,可是對象頭信息是與對象自身定義的數據無關額外的存儲成本,考慮到虛擬機的空間效率。Mark work被設計成一個非固定的數據結構以便在極小空間內存儲盡可能多的信息,他會依據對象狀態復用自己的存儲空間。
對象頭的還有一部分是類型指針,即對象指向他的類元數據的指針。虛擬機通過這個指針來確定這個對象是哪個類的實例。
假設對象是一個Java數組,那在對象中還必須有一塊用于記錄數組長度的數據。因為虛擬機可通過普通 Java對象的元數據信息確定Java對象的大小,可是從數組的元數據中卻無法確定數組的大小。
接下來的實例數據是對象真正存儲的有效信息。也是在程序代碼中所定義的各種類型的字段內容。不管是從父類繼承下來的還是在子類中定義的,都須要記錄下來。這部分的存儲順序會受到虛擬機分配策略參數和字段在Java源代碼中定義順序的影響。
Hotspot虛擬機的分配策略是同樣寬度的字段總是被分配到一起。在滿足這個前提條件下。在父類中定義的變量會出如今子類之前。
## 對象的訪問定位
建立對象是為了使用對象,我們的Java程序須要通過棧上的reference數據來操作堆上的詳細對象。因為reference類型在Java虛擬機規范中僅僅規定了一個指向對象的引用。并未定義這個引用應該通過何種方式去定位、訪問堆中對象的詳細位置。所以對象訪問方式也是取決于虛擬機實現而定的。眼下主流的訪問方式有兩種使用句柄和直接指針
### 使用句柄
Java堆會中將會劃分出一塊內存作為句柄池,reference中存儲的就是對象的句柄地址,而句柄中包括了對象實例數據與類型數據各自詳細的地址信息。
Java堆會中將會劃分出一塊內存作為句柄池。reference中存儲的就是對象的句柄地址,而句柄中包括了對象實例數據與類型數據各自詳細的地址信息。

### 使用直接指針
Java堆對象的布局中必須考慮怎樣設置訪問類型數據的信息,而reference中存儲的直接就是對象地址

這兩種對象訪問方式各有優勢,使用句柄訪問的最大優點就是reference中存儲的是穩定的句柄地址,在對象被移動(垃圾收集時移動對象是很普遍的行為)時僅僅會改變句柄中實例數據指針。而reference本身不須要改動。
使用直接指針的最大優點是速度快,他節省了一次指針定位的時間開銷。因為對象的訪問在Java中很頻繁,因此這類開銷積少成多也是很可觀的。
- java
- 設計模式
- 設計模式總覽
- 設計原則
- 工廠方法模式
- 抽象工廠模式
- 單例模式
- 建造者模式
- 原型模式
- 適配器模式
- 裝飾者模式
- 代理模式
- 外觀模式
- 橋接模式
- 組合模式
- 享元模式
- 策略模式
- 模板方法模式
- 觀察者模式
- 迭代子模式
- 責任鏈模式
- 命令模式
- 備忘錄模式
- 狀態模式
- 訪問者模式
- 中介者模式
- 解釋器模式
- 附錄
- JVM相關
- JVM內存結構
- Java虛擬機的內存組成以及堆內存介紹
- Java堆和棧
- 附錄-數據結構的堆棧和內存分配的堆區棧區的區別
- Java內存之Java 堆
- Java內存之虛擬機和內存區域概述
- Java 內存之方法區和運行時常量池
- Java 內存之直接內存(堆外內存)
- JAVA內存模型
- Java內存模型介紹
- 內存模型如何解決緩存一致性問題
- 深入理解Java內存模型——基礎
- 深入理解Java內存模型——重排序
- 深入理解Java內存模型——順序一致性
- 深入理解Java內存模型——volatile
- 深入理解Java內存模型——鎖
- 深入理解Java內存模型——final
- 深入理解Java內存模型——總結
- 內存可見性
- JAVA對象模型
- JVM內存結構 VS Java內存模型 VS Java對象模型
- Java的對象模型
- Java的對象頭
- HotSpot虛擬機
- HotSpot虛擬機對象探秘
- 深入分析Java的編譯原理
- Java虛擬機的鎖優化技術
- 對象和數組并不是都在堆上分配內存的
- 垃圾回收
- JVM內存管理及垃圾回收
- JVM 垃圾回收器工作原理及使用實例介紹
- JVM內存回收理論與實現(對象存活的判定)
- JVM參數及調優
- CMS GC日志分析
- JVM實用參數(一)JVM類型以及編譯器模式
- JVM實用參數(二)參數分類和即時(JIT)編譯器診斷
- JVM實用參數(三)打印所有XX參數及值
- JVM實用參數(四)內存調優
- JVM實用參數(五)新生代垃圾回收
- JVM實用參數(六) 吞吐量收集器
- JVM實用參數(七)CMS收集器
- JVM實用參數(八)GC日志
- Java性能調優原則
- JVM 優化經驗總結
- 面試題整理
- 面試題1
- java日志規約
- Spring安全
- OAtuth2.0簡介
- Spring Session 簡介(一)
- Spring Session 簡介(二)
- Spring Session 簡介(三)
- Spring Security 簡介(一)
- Spring Security 簡介(二)
- Spring Security 簡介(三)
- Spring Security 簡介(四)
- Spring Security 簡介(五)
- Spring Security Oauth2 (一)
- Spring Security Oauth2 (二)
- Spring Security Oauth2 (三)
- SpringBoot
- Shiro
- Shiro和Spring Security對比
- Shiro簡介
- Session、Cookie和Cache
- Web Socket
- Spring WebFlux