天天看點

Java 記憶體管理機制,深入了解JVM

概述:在JVM的自動記憶體管理機制的支援下,不需要為每一個new的對象進行delete/free。本文将讨論在記憶體溢出和溢出方面的問題以及資料存放區域。

常見異常:

StackOverFloeError(線程請求棧的深度大于JVM允許的Max Value)

OutOfMemoryError(動态擴充是大于JVM允許的Max Value,注意,這個時候是在擴充,上一個錯誤是在請求)。

一:資料存放區域。

1.方法區:method Area

這個區域線程共享。存放類加載資訊,常量,靜态變量,JIT編譯後的代碼。

裡面有運作時常量池,包含符号引用等。

這個區域會出:OutOfMemoryError

2.虛拟機棧 :VM Stack

這個區域是線程私有的。

當方法被執行的時候,這個時候在該區域會建立一個Stack Frame存儲局部變量表,操作棧,動态連結,方法出口等資訊。一個方法的執行也就意味着一個棧幀在VM Stack裡面從入棧到出棧的過程。

這個區域我們着重考慮局部變量表,裡面存放了各種的資料類型,隻有64位的long和double占用2個局部變量空間,其他的都是一個。

異常:StackOverFloeError,OutOfMemoryError.

3.本地方法棧:Native Method Stack

與虛拟機棧相似,隻是他是為Native方法服務,但是虛拟機棧為Java方法(也就是位元組碼)提供服務。

4.程式計數器:Program Couter Register

該區域較小,可以看做是目前線程的位元組碼行号訓示器,用來選擇下一條需要執行的語句。

線程管理:由于線程切換需要恢複到正常的執行的位置,是以一個線程就需要一個程式計數器(線程私有)。

5.堆:Heap

這個區域線程共享。在JVM建立的時候就建立了。對象執行個體,數組都在這裡進行配置設定。

Java的垃圾回收區域也存放在這個區域(Garbage Collected Heap,采用分代收集算法,詳情百度)。

這個區域也會出這個錯誤:OutOfMemoryError

6.直接記憶體:Direct Memory

這個區域獨立于堆,可以直接使用Native函數配置設定堆外記憶體。

每個區域都有建立和銷毀的時間,都有各自的用途。

一個面試題:解釋記憶體中的棧(stack)、堆(heap)和方法區(method area)的用法。

答:通常我們定義一個基本資料類型的變量,一個對象的引用,還有就是函數調用的現場儲存都使用JVM中的棧空間;而通過new關鍵字和構造器建立的對象則放在堆空間,堆是垃圾收集器管理的主要區域,由于現在的垃圾收集器都采用分代收集算法,是以堆空間還可以細分為新生代和老生代,再具體一點可以分為Eden、Survivor(又可分為From Survivor和To Survivor)、Tenured;方法區和堆都是各個線程共享的記憶體區域,用于存儲已經被JVM加載的類資訊、常量、靜态變量、JIT編譯器編譯後的代碼等資料;程式中的字面量(literal)如直接書寫的100、”hello”和常量都是放在常量池中,常量池是方法區的一部分,。棧空間操作起來最快但是棧很小,通常大量的對象都是放在堆空間,棧和堆的大小都可以通過JVM的啟動參數來進行調整,棧空間用光了會引發StackOverflowError,而堆和常量池空間不足則會引發OutOfMemoryError。

二:對象通路。

Object obj = new Object(); // Object obj放在本地變量中,new的對象放在堆裡面。

Java 記憶體管理機制,深入了解JVM
Java 記憶體管理機制,深入了解JVM
通路方式 句柄通路 直接通路
好處 位址穩定,對象被移動時改變的隻是執行個體化的資料指針,reference本身不修改 速度很快

三:常見的錯誤産生

OutOfMemoryError
 模拟條件:while死循環建立對象,導緻Heap溢出,産生OutOfMemoryError 
 StackOverFlow
建立大量變量(虛拟棧)