1. 在JAVA中,對象的分配一般使用new關鍵字。
當虛擬機遇到new指令時,會先檢查該指令所包含的參數在常量池中能否找到一個符號引用,並檢查該符號引用所代表的類是否被加載、解析和初始化。
如果沒有,則會先執行類的加載過程。
2. 類加載完成后,會為該對象分配內存空間。一個對象需要多大的內存空間在類加載完成后就確定了。
分配內存有兩種方法,依據內存空間是否規整來確定。
如果被內存空間是規整的,只要把空閑指針向空閑內存方向挪動即可,這種方法稱為“指針碰撞”;
如果內存空間不是規整的,需要有一個“空閑列表”用於記錄哪些內存是可用的,並從可用內存中分配足夠大小的內存出來,並修改“空閑列表”;
在使用Serial、ParNew等算法時是用的指針碰撞;使用Mark-Sweep等算法時,采用空閑列表。
3. 在多線程環境下怎么保證分配內存的動作是線程安全的。
一種方法是對分配內存的動作進行同步;
另一種方法是使用“本地線程分配緩存(TLAB)”,每個線程會預先分配到一塊內存,申請內存會在各自的TLAB上進行;只有當TLAB不夠是,才需要同步分配新的TLAB;
4. 分配好內存后,虛擬機會將除對象頭以外的空間初始化為0。這就是為什么JAVA代碼中的全局變量可以不用初始化也可以使用的原因。
此外,虛擬機還會對對象頭進行必要的設置,比如對象所屬的類,對象的哈希碼,對象的GC分代年齡等信息。
5. 上述過程完成或,虛擬機認為一個對象已經創建完畢,但是從程序來看,對象還沒有初始化,因此需要根據代碼初始化各個變量。
這一步完成后,一個可用的對象就創建好了。