1. 程式人生 > >java虛擬機器的記憶體劃分

java虛擬機器的記憶體劃分

一.java虛擬機器記憶體劃分

Java的JVM的記憶體可分為3個區:堆(heap)、棧(stack)和方法區(method)。

  1. 棧區

    a.每個執行緒包含一個棧區,棧中只儲存方法中(不包括物件的成員變數)的基礎資料型別和自定義物件的引用(不是物件),物件都存放在堆區中;

    b.每個棧中的資料(原始型別和物件引用)都是私有的,其他棧不能訪問;

    c.棧分為3個部分:基本型別變數區、執行環境上下文、操作指令區(存放操作指令)。

  2. 堆區

    a.儲存的全部是物件例項,每個物件都包含一個與之對應的class的資訊(class資訊存放在方法區);

    b.jvm只有一個堆區(heap)被所有執行緒共享,堆中不存放基本型別和物件引用,只存放物件本身,幾乎所有的物件例項和陣列都在堆中分配。

  3. 方法區

    又叫靜態區,跟堆一樣,被所有的執行緒共享。它用於儲存已經被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。

二.Java虛擬機器執行時資料區域

Java程式執行過程:
首先Java原始碼檔案(.java字尾)會被Java編譯器編譯為位元組碼檔案(.class字尾),然後由JVM中的類載入器載入各個類的位元組碼檔案,載入完畢之後,交由JVM執行引擎執行。在整個程式執行過程中,JVM會用一段空間來儲存程式執行期間需要用到的資料和相關資訊,這段空間一般被稱作為Runtime Data Area(執行時資料區),也就是我們常說的JVM記憶體。

因此,在Java中我們常常說到的記憶體管理就是針對這段空間進行管理(如何分配和回收記憶體空間)。

java虛擬機器管理的記憶體包括幾個執行時資料記憶體:堆、方法區、虛擬機器棧、本地方法棧、程式計數器,其中方法區和堆是由執行緒共享的資料區,其他幾個都是執行緒隔離的資料區。
這裡寫圖片描述

  1. java虛擬機器棧

    虛擬機器棧描述的是java方法執行的記憶體模型:每個方法在執行的同時都會建立一個棧幀用於儲存區域性變量表、運算元棧、動態連結、方法出口等資訊。每個方法從呼叫直至完成的過程,就對應著一個棧幀在虛擬機器棧中入棧到出棧的過程。

    棧記憶體就是虛擬機器棧,或者說是虛擬機器棧中區域性變量表的部分。

    區域性變量表存放了編輯期可知的各種基本資料型別(boolean、byte、char、short、int、float、long、double)、引用物件(reference)型別和returnAddress型別(指向了一條位元組碼指令的地址)。

    其中64位長度的long和double型別的資料會佔用兩個區域性變數的空間,其餘的資料型別只佔用一個。

  2. 本地方法棧

    本地方法棧和虛擬機器棧發揮的作用是非常類似的,他們的區別是虛擬機器棧為虛擬機器執行java方法(也就是位元組碼服務),而本地方法棧則為虛擬機器使用到的Native方法服務。

    本地方法棧區域也會丟擲StackOverflowError和OutOfMemoryError異常。

  3. 程式計數器

    程式計數器是一塊較小的記憶體,它可以看作是當前執行緒所執行的行號指示器。位元組碼直譯器工作的時候就是通過給編這個計數器值來選取下一條需要執行的位元組碼指令,分支、迴圈、跳轉、異常處理、執行緒恢復等基礎功能都需要依賴這個計數器來完成。如果執行緒正在執行的是一個java方法,這個計數器記錄的是正在執行的虛擬機器位元組碼指令的地址;如果正在執行的是Native方法,這個計數器則為空。此記憶體區域是唯一一個在java虛擬機器規範中沒有規定任何OutOfMemoryError情況的區域。

  4. java堆

    堆是java虛擬機器所管理的記憶體中最大的一塊。java堆是被所有執行緒共享的一塊記憶體區域,在虛擬機器啟動的時候建立,此記憶體區域的唯一目的就是存放物件例項,幾乎說有的物件例項都在這裡分配記憶體。所有的物件例項和陣列都在堆上分配。

    java堆是垃圾收集器管理的主要區域。java堆細分為新生代和老年代。

    不管怎樣,劃分的目的都是為了更好地回收記憶體,或者更快的分配記憶體。

    java堆可以處於物理上不連續的記憶體空間中,只要邏輯上是連續的即可。如果堆中沒有完成例項分配,並且堆也無法再擴充套件時將丟擲OutOfMemoryError異常。

  5. 方法區

    方法區它用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。

    除了java堆一樣不需要連續的記憶體和可以選擇固定大小或者可擴充套件外,還可以選擇不實現垃圾收集。這個區域的記憶體回收目標主要是針對常量池的回收和堆型別的解除安裝。

  6. 執行時常量池

    它是方法區的一部分。Class檔案中除了有關的版本、欄位、方法、介面等描述資訊外,還有一項資訊是常量池,用於存放編輯器生成的各種字面量和符號引用,這部分內容將在類載入後進入方法區的執行時常量池中存放。

    java語言並不要求常量一定只有編輯器才能產生,也就是可能將新的常量放入池中,這種特性被開發人員利用的比較多的便是String類的intern()方法。

    當常量池無法再申請到記憶體時會丟擲OutOfMemoryError異常。