《Java 底層原理》Java內存模型

前言

通過JDK原理來重新理解一遍Java內存模型,通過其他方式學習到,總會有錯誤或者遺漏的情況。

內存模型

Java常常被提到的4個概念:

class文件:硬盤上的.class文件

class content:類加載器將.clas文件加載入內存,存儲字節碼文件數據的那塊內存區域

Class對象:Class clazz = Test.class;

Java對象 new關鍵字或者其他方式產生的實體對象:例如 Test obj = new Test();

Java內存結構圖:

1. 方法區:JDK8及之後通過元空間實現,元空間使用的OS內存,存放的內容爲:類名,方法名,屬性名,變量名,static 等等

2. 本地方法棧:JNI,Java調用c++方法的鏈接庫,Java native方法的調用。

3. 虛擬機棧:一個線程一個虛擬機棧,一個虛擬機棧裏面方法調用的次數個棧幀。

        棧幀包含:

    局部變量:方法裏面的變量信息(int a = 0; int b = 1 這類信息的a 和 b 信息記錄的地方)。

              操作數棧:方法裏面的 a+b , a = 4,等等這類操作的信息。

              動態鏈接:mian方法對應的Jvm對象在元空間的內存地址。

              返回地址:保存現場,保存上一個方法的調用完這個方法(test)的下一個程序計數器,保證後續方法執行完成之後,後面的代碼可以繼續執行。

              附加信息:

        JVM運行test方法,內部是怎麼做的?

                第一步、創建test的方法的棧幀

                第二步、在test方法的棧幀中保存上一個方法的字節碼的下一行程序計數器(比如:21)

                第三步、線程的局部表開始指針(上一個方法的)保存至add方法的棧幀

                第四步、線程的操作數棧開始指針(上一個方法的)保存至add方法的棧幀, 1,2,3這3步表示保存現場。

                第五步、將test方法的局部表指針賦值給線程的局部表指針

                第六步、將test方法的操作數棧指針賦值給線程的操作數棧指針

4. 程序計數器:字節碼的索引(EIP,RIP)

Java 各個內存之間的引用關係

  • 虛擬機棧指向方法區:動態鏈接,例如:test.mian()方法。
  • 虛擬機棧指向堆區:對象的引用變量,例如:Test obj = new Test();
  • 方法區指向堆區:引用類型的靜態屬性,例如static Test = new Test(),Test在堆區,static 在方法區。
  • 堆區指向方法區:對象的內存佈局Klass的信息部分存在方法區。

Jvm 源碼中的內存分佈:(Cheap,ValueObj,AllStatic)

class CHeapObj {
 public:
  void* operator new(size_t size) throw();
  void  operator delete(void* p);
  void* new_array(size_t size);
};


// Base class for objects used as value objects.
// Calling new or delete will result in fatal error.

class ValueObj {
 public:
  void* operator new(size_t size) throw();
  void operator delete(void* p);
};

// Base class for classes that constitute name spaces.

class AllStatic {
 public:
  void* operator new(size_t size) throw();
  void operator delete(void* p);
};

總結

學習內存結構,就是爲了解決我們工作的問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章