概述:在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的對象放在堆裡面。
通路方式 | 句柄通路 | 直接通路 |
---|---|---|
好處 | 位址穩定,對象被移動時改變的隻是執行個體化的資料指針,reference本身不修改 | 速度很快 |
三:常見的錯誤産生
OutOfMemoryError
模拟條件:while死循環建立對象,導緻Heap溢出,産生OutOfMemoryError
StackOverFlow
建立大量變量(虛拟棧)