一、JAVA虛擬機器器------JVM自動記憶體管理

2021-03-10 12:00:07

一、JAVA記憶體區與記憶體溢位

1.1 概述

java程式設計師在JVM自動記憶體管理機制的條件下,不需要為每一個new的操作去寫配對的delete/free程式碼,雖然這樣可以省去很多麻煩,但是正是因為我們吧物件的建立交給JVM去管理,所以一旦出現記憶體漏失和溢位的問題,如果我們對jvm瞭解的不深入那我們在修正這些問題是會遇到很多麻煩

1.2 執行時資料區

上一張大家都見過的圖

在這裡插入圖片描述

1.2.1 程式計數器 (Program Counter Register)

  1. 程式計數器是一塊佔用記憶體比較小的空間,可以看成是當前執行緒所執行的位元組碼的行號指示器(可以用電梯的指示樓層號訊號燈來比喻),位元組碼直譯器工作時就是通過改變當前程式計數器的值來選取下一條要執行的位元組碼指令,程式計數器是程式控制流的指示器,
    分支、迴圈、跳轉、例外處理、執行緒恢復等基礎功能都是依賴程式計數器來完成的。Java虛擬機器器的多執行緒是通過執行緒輪流切換、分配處理器的執行時間來實現的,在任意一個確定的時間內 一個處理器只會執行一個執行緒(多核處理器理解成為一個核心)中的指令,因此為了執行緒切換後能恢復到正確的執行位置,所以每個執行緒都有一個獨立的程式計數器,每個執行緒的計數器互不影響,獨立記憶體。所以也被稱為執行緒私有的

1.2.2 Java虛擬機器器棧(Java Virtual Machine Stack)

  1. 與程式計數器一樣 Java虛擬機器器棧也是執行緒私有的,它的生命週期與執行緒相同。虛擬機器器棧描述的是Java的方法執行的執行緒模型:每個方法被執行的時候都會同步的建立一個棧幀用於儲存區域性變數表、運算元棧、動態連結、方法出口等資訊。每一個方法從被呼叫到執行結束的過程,也就是棧幀從入棧到出棧的過程
  2. 很多程式設計師都把JVM的記憶體籠統的歸結為 「堆記憶體」和「棧記憶體」,其實本質上JVN的記憶體區域比這個籠統的說法要複雜很多,這也說明了大家對 「堆記憶體」和「棧記憶體」非常感興趣~~ 其實「」通常就是指的Java虛擬機器器棧,但是更多的情況下是指的Java虛擬機器器中的區域性變數表的部分
  3. 區域性變數表中存放了可知的JAVA 基礎資料型別 (boolean 、byte 、char、 short、int、float、long、double)、物件參照(reference型別,它可能並不等同於物件本身,可能是指向物件原始地址的參照指標等)
  4. 在Java虛擬機器器中有兩類異常情況
    1. StackOverFolwError: 當執行緒請求的棧的深度大於虛擬機器器允許的最大深度時
    2. OutOfMemoryError: 如果虛擬機器器的棧容量可以進行動態擴充套件,當虛擬機器器申請不到足夠的棧記憶體時,會丟擲異常。俗稱OOM

1.2.3 本地方法棧 (Native Method Stacks)

本地方法棧和Java虛擬機器器棧的作用非常相似,只不過Java虛擬機器器棧是為JAVA方法(位元組碼)進行服務,而本地方法棧則是為虛擬機器器使用到的本地方法進行服務,值得注意的是在我們常用的Hot-Spot虛擬機器器直接把本地方法棧和Java虛擬機器器棧合二為一了,所以在Hot-Spot虛擬機器器中當本地方法棧無法申請到記憶體時,也會丟擲StackOverFolwError、OutOfMemoryError這兩個異常

1.2.4 Java堆 (Java Heap)

Java堆是jvm管理的最大一片記憶體區域,Java堆是被所有執行緒共用的一塊記憶體區域,虛擬機器器啟動時堆記憶體就被建立,堆記憶體被建立的唯一原因就是存放記憶體範例 在Java 中幾乎所有的的記憶體都在這裡分配記憶體,這裡提到了幾乎一詞,在Java虛擬機器器規範中對堆的描述是:「所有物件的範例和陣列都應當在堆上分配」,但是隨著Java語言的發展,即時編譯技術的發展等,所以java 範例都在堆上分配也就沒有那麼絕對了。

1.2.5 方法區(Method Area)

  1. 方法區和Java堆是一樣的 也是執行緒共用的一塊記憶體區域它用於儲存已被虛擬機器器載入的型別資訊、常數、靜態變數、即時編譯器編譯後的程式碼快取等資料 雖然JVM虛擬機器器規範中吧方法區表述為堆的一個邏輯區域,但是他有一個別名叫做非堆,目的是與Java堆區分開。
  2. 這裡應該提到一下永久代的概念 JDK8之前許多程式設計師喜歡把方法區稱之為永久代,將兩者混為一談,實際上是因為當時Hot-Spot的設計團隊把收集器的分代設計延伸到了方法區中,或者說用永久代的概念去實現方法區,這樣就可以使用收集器 管理Java堆一樣的管理方法區了,但是在JDK8之後 引入了一個名詞叫做元空間來替代了之前的永久代,而之前的方法區改為了現在有本地記憶體來實現方法區。

1.2.5.1 執行時常數池(Runtime Constant Pool)

  1. 執行時常數池也是方法區的一部分,Class檔案中除了有類的版本、欄位、方法、介面等描述資訊外,還有一項資訊是常數池表用於生成編譯期間生成的各種字面量和符號參照這部分的內容會再類載入之後存放到方法區的執行時常數池中
  2. 執行時常數池相比較於Class檔案常數池的另外一個重要的特徵就是具備動態性。Java語言並不要求常數只有編譯時才能產生,執行期間也可以吧新的常數放入常數池中 這裡比較常用的就是String類的Intern()方法。

String類的Intern方法簡介
在這裡插入圖片描述
當我們後面再次參照假設 我們後面String str4 = new String(「aaa」); 那使用 str4.intern() 時,如果常數池中存在「aaa」 那個就回直接使用常數池的「aaa」

temp 還有後續

二、垃圾收集器與記憶體分配策略

三、虛擬機器器效能監控、故障處理工具