虛擬機遇到一條new指令,首先去檢查這個指令的參數可否在Metaspace的常量池中定位到一個類的符號引用,而且檢查這個符號引用表明的類是否已經被加載、解析和初始化。( 即判斷類元信息是否存在)。若是沒有,那麼在雙親委派模式下,使用當前類加載器以ClassLoader+包名+類名爲Key進行查找對應的.class文件。若是沒有找到文件,則拋出ClassNotFoundException異常,若是找到,則進行類加載,並生成對應的Class類對象java
首先計算對象佔用空間大小,接着在堆中劃分一塊內存給新對象。 若是實例成員變量是引用變量,僅分配引用變量空間便可,即4個字節大小。git
說明:選擇哪一種分配方式由Java堆是否規整決定,而Java堆是否規整又由所採用的垃圾收集器是否帶有壓縮整理功能決定。程序員
給對象的屬性賦值的操做:
① 屬性的默認初始化
② 顯式初始化
③ 代碼塊中初始化
④ 構造器中初始化 github
在分配內存空間時,另一個問題是及時保證new對象時候的線程安全性:建立對象是很是頻繁的操做,虛擬機須要解決併發問題。虛擬機採用 了兩種方式解決併發問題:算法
內存分配結束,虛擬機將分配到的內存空間都初始化爲零值(不包括對象頭)。這一步保證了對象的實例字段在Java代碼中能夠不用賦初始值就能夠直接使用,程序能訪問到這些字段的數據類型所對應的零值。數組
將對象的所屬類(即類的元數據信息)、對象的HashCode和對象的GC信息、鎖信息等數據存儲在對象的對象頭中。這個過程的具體設置方式取決於JVM實現。安全
在Java程序的視角看來,初始化才正式開始。初始化成員變量,執行實例化代碼塊,調用類的構造方法,並把堆內對象的首地址賦值給引用變量。 所以通常來講(由字節碼中是否跟隨有invokespecial指令所決定),new指令之 後會接着就是執行方法,把對象按照程序員的意願進行初始化,這樣一個真正可用的對象纔算徹底建立出來。bash
/**
* 測試對象實例化的過程
* ① 加載類元信息 - ② 爲對象分配內存 - ③ 處理併發問題 - ④ 屬性的默認初始化(零值初始化)
* - ⑤ 設置對象頭的信息 - ⑥ 屬性的顯式初始化、代碼塊中初始化、構造器中初始化
*
* 給對象的屬性賦值的操做:
* ① 屬性的默認初始化 - ② 顯式初始化 / ③ 代碼塊中初始化 - ④ 構造器中初始化
*
*/
public class Customer{
int id = 1001;
String name;
Account acct;
{
name = "匿名客戶";
}
public Customer(){
acct = new Account();
}
}
class Account{
}
複製代碼
包含兩部分網絡
說明:它是對象真正存儲的有效信息,包括程序代碼中定義的各類類型的字段(包括從父類繼承下來的和自己擁有的字段) 規則:併發
不是必須的,也沒特別含義,僅僅起到佔位符做用
public class CustomerTest {
public static void main(String[] args) {
Customer cust = new Customer();
}
}
複製代碼
JVM是如何經過棧幀中的對象引|用訪問到其內部的對象實例的呢?-> 定位,經過棧上reference訪問
對象訪問的主要方式有兩種
句柄訪問
直接指針(HotSpot採用)
/**
* IO NIO (New IO / Non-Blocking IO)
* byte[] / char[] Buffer
* Stream Channel
*
* 查看直接內存的佔用與釋放
*/
public class BufferTest {
private static final int BUFFER = 1024 * 1024 * 1024;//1GB
public static void main(String[] args){
//直接分配本地內存空間
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
System.out.println("直接內存分配完畢,請求指示!");
Scanner scanner = new Scanner(System.in);
scanner.next();
System.out.println("直接內存開始釋放!");
byteBuffer = null;
System.gc();
scanner.next();
}
}
複製代碼
來源於NIO,經過存在堆中的DirectByteBuffer操做Native內存
一般,訪問直接內存的速度會優於Java堆。即讀寫性能高
也可能致使OutOfMemoryError異常:OutOfMemoryError: Direct buffer memory
/**
* 本地內存的OOM: OutOfMemoryError: Direct buffer memory
*/
public class BufferTest2 {
private static final int BUFFER = 1024 * 1024 * 20;//20MB
public static void main(String[] args) {
ArrayList<ByteBuffer> list = new ArrayList<>();
int count = 0;
try {
while(true){
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
list.add(byteBuffer);
count++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
System.out.println(count);
}
}
}
複製代碼
簡單理解: java process memory = java heap + native memory
【代碼】
github.com/willShuhuan…
【筆記】
JVM_01 簡介
JVM_02 類加載子系統
JVM_03 運行時數據區1- [程序計數器+虛擬機棧+本地方法棧]
JVM_04 本地方法接口
JVM_05 運行時數據區2-堆
JVM_06 運行時數據區3-方法區
JVM_07 運行時數據區4-對象的實例化內存佈局與訪問定位+直接內存
JVM_08 執行引擎(Execution Engine)
JVM_09 字符串常量池StringTable
JVM_10 垃圾回收1-概述+相關算法
JVM_11 垃圾回收2-垃圾回收相關概念
JVM_12 垃圾回收3-垃圾回收器