2. Java 內存區域與內存溢出異常

概述

Java 對於 C 和 C++ 來說存在一個很好的特性就是在虛擬機的自動內存管理機制的幫助下,不需要爲每一個 new 操作去寫配對的 delete/free 代碼,而且**不容易** 出現內存泄漏和內存溢出問題。注意這裏說的是不容易,所以還是有可能會出現的。那麼當出現的時候就需要你能夠排查和解決掉錯誤。

運行時數據區域

Java 虛擬機在執行程序的過程中會把所管理的內存劃分爲若干個不同的數據區域。每個區域用途不同,生命週期也不同,或隨虛擬機進程產生和銷燬,或隨用戶線程產生和銷燬。其中有所有線程共享的數據區有:方法區(Method Area)、堆(Heap)線程隔離的數據區有:虛擬機棧(VM Stack)、本地方法棧(Native Method Stack)、程序計數器(Program Couter Register)

程序計數器

在學操作系統的時候,我們知道進程是資源分配的基本單位,進程是調度的基本單位。線程基本上不擁有系統資源只擁有一些必不可少的資源其中就包括程序計數器。程序計數器的作用是當前線程所執行的字節碼的行號指示器。Java 虛擬機的多線程是通過線程輪流切換並分配處理器的執行時間的方式來實現的,在任何一個確定的時刻,一個處理器只會執行一條線程中的指令。

Java 虛擬機棧

Java 虛擬機棧也是線程私有的,生命週期與線程相同。虛擬機棧描述的是 Java 方法執行的內存模型:每個方法被執行的時候都會同時創建一個棧幀(Stack Frame)用於存儲局部變量表、操作棧、動態鏈接、方法出口等信息。每一個方法被調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。

一般在面試中都會問到關於Java 內存分區中的堆內存(Heap)與棧內存(Stack)問題。我曾經簡單的以爲就是數據結構中的棧一樣呢。分爲這兩種分區是比較粗糙的分法,實際的情況比這更加複雜。“棧”就是虛擬機棧,或指的是虛擬機棧中的局部變量表部分。局部變量表所需的內存空間是在編譯期間完成分配的,在運行期間不會改變大小。

在這個區域會產生兩種異常的情況,一是 如果線程請求的棧的深度大於虛擬機所允許的深度,將拋出 StackOverflowError 異常,二是 如果虛擬機棧可以動態擴展,當擴展時無法申請到足夠的內存時會拋出 OutOfMemoryError 異常。

本地方法棧

Native Method Stacks 與虛擬機棧所發揮的作用是非常相似的,虛擬機棧爲虛擬機執行Java 方法服務,本地方法棧爲虛擬機使用到的 Native 方法服務。因爲虛擬機沒有對本地方法棧中的方法是用的語言等強制規定,Sun HotSpot 將兩者合二爲一,本地方法棧區域同樣會拋出 上述兩種異常。

Java 堆

Java 堆(Java Heap)的幾個特點

  1. Java 虛擬機所管理的內存中的最大一塊
  2. 被所有線程共享的一塊內存區域
  3. 虛擬機啓動時創建
  4. 唯一目的存放對象實例
  5. 垃圾收集器管理的主要區域,也被稱爲 “GC堆”
  6. 可處於物理上不連續的內存空間
  7. 處於邏輯上連續的內存空間

在Java 規範中描述的是:素有的對象實例以及數組都要在堆上分配。但是目前來看不再是那麼絕對了。

方法區

作用:存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。

特點:邏輯上是Java 堆的一部分,但是別名叫做 Non-Heap(非堆)。它不需要連續的物理內存和可以選擇固定大小或者可擴展,並且可以選擇不實現垃圾收集。

當方法區無法滿足內存分配需求時,將會拋出 OutOfMemoryError 異常。運行時常量池也是方法區的一部分,當常量池無法申請到內存時會拋出 OutOfMemoryError 異常。

直接內存

它不是虛擬機運行時數據區的一部分,也不是Java 虛擬機規範中定義的內存區域。當各個內存區域的總和大於物理內存限制,從而導師動態擴展時出現 OutOfMemoryError 異常。

對象訪問

通過一句代碼來看:

Object obj = new Object()

Object obj 這部分語義反映到 Java 棧的本地變量表中,作爲一個 reference 類型數據出現。 new Object() 這部分的語義將會反映到 Java 堆中,形成一塊存儲了 Object 類型所有實例數據值的結構化內存,此內存長度不固定。虛擬機訪問對象的方式主要分爲兩種:

  • 使用句柄
  • 直接指針

句柄訪問優勢在於 reference 中存儲的時穩定的句柄地址,在對象被移動時只會改變句柄中的實例數據指針,而 reference 本身不需要修改。

直接指針訪問的優勢在於 速度更快,它節省了一次指針定位的時間開銷。

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