JAVA的內存模型及結構
所有的Java開發人員可能會遇到這樣的困惑?我該為堆內存設置多大空間呢?OutOfMemoryError的異常到底涉及到運行時數據的哪塊區域?該怎麼解決呢?
Java內存模型在JVM specification, Java SE 7 Edition, and mainly in the chapters “2.5 Runtime Data Areas” and “2.6 Frames”中有詳細的說明。對象和類的數據存儲在3個不同的內存區域:堆(heap space)、方法區(method area)、本地區(native area)。
堆內存存放對象以及數組的數據,方法區存放類的信息(包括類名、方法、字段)、靜態變量、編譯器編譯後的代碼,本地區包含線程棧、本地方法棧等存放線程

方法區有時被稱為持久代(PermGen)。
所有的對象在實例化後的整個運行周期內,都被存放在堆內存中。堆內存又被劃分成不同的部分:伊甸區(Eden),幸存者區域(Survivor Sapce),老年代(Old Generation Space)。
方法的執行都是伴隨著線程的。原始類型的本地變量以及引用都存放在線程棧中。而引用關聯的對象比如String,都存在在堆中。為了更好的理解上麵這段話,我們可以看一個例子:
01 |
import java.text.SimpleDateFormat;
|
02 |
import java.util.Date;
|
03 |
04 |
import org.apache.log4j.Logger;
|
05 |
06 |
public class HelloWorld {
|
07 |
private static Logger LOGGER = Logger.getLogger(HelloWorld. class .getName());
|
08 |
09 |
public void sayHello(String message) {
|
10 |
SimpleDateFormat formatter = new SimpleDateFormat( "dd.MM.YYYY" );
|
11 |
String today = formatter.format( new Date());
|
12 |
LOGGER.info(today + ": " + message);
|
13 |
}
|
14 |
} |
這段程序的數據在內存中的存放如下:
通過JConsole工具可以查看運行中的Java程序(比如Eclipse)的一些信息:堆內存的分配,線程的數量以及加載的類的個數;
這裏有一份極好的白皮書:Memory Management in the Java HotSpot Virtual Machine。它描述了垃圾回收(GC)觸發的內存自動管理。Java的內存結構包含如下部分:
堆內存
堆內存同樣被劃分成了多個區域:
- 包含伊甸(Eden)和幸存者區域(Survivor Sapce)的新生代(Young generation)
- 老年代(Old Generation)
不同區域的存放的對象擁有不同的生命周期:
- 新建(New)或者短期的對象存放在Eden區域;
- 幸存的或者中期的對象將會從Eden區域拷貝到Survivor區域;
- 始終存在或者長期的對象將會從Survivor拷貝到Old Generation;
生命周期來劃分對象,可以消耗很短的時間和CPU做一次小的垃圾回收(GC)。原因是跟C一樣,內存的釋放(通過銷毀對象)通過2種不同的GC實現:Young GC、Full GC。
為了檢查所有的對象是否能夠被銷毀,Young GC會標記不能銷毀的對象,經過多次標記後,對象將會被移動到老年代中。
哪兒的OutOfMemoryError
對內存結構清晰的認識同樣可以幫助理解不同OutOfMemoryErrors:
Exception in thread “main”: java.lang.OutOfMemoryError: Java heap space
Exception in thread “main”: java.lang.OutOfMemoryError: PermGen space
原因:類或者方法不能被加載到老年代。它可能出現在一個程序加載很多類的時候,比如引用了很多第三方的庫;
Exception in thread “main”: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
原因:創建的數組大於堆內存的空間
Exception in thread “main”: java.lang.OutOfMemoryError: request <size> bytes for <reason>. Out of swap space?
原因:分配本地分配失敗。JNI、本地庫或者Java虛擬機都會從本地堆中分配內存空間。
Exception in thread “main”: java.lang.OutOfMemoryError: <reason> <stack trace>(Native method)
原因:同樣是本地方法內存分配失敗,隻不過是JNI或者本地方法或者Java虛擬機發現;
關於OutOfMemoryError的更多信息可以查看:“Troubleshooting Guide for HotSpot VM”, Chapter 3 on “Troubleshooting on memory leaks”
參考鏈接:
- Provides Java HotSpot information about VM Options and environment variables
-
Troubleshooting Guide for HotSpot VM
An exhaustive guide for memory leaks, system crashes, hangings, loops, signal and exception handling. -
Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning
Ergonomics and tuning goals, generations sizing using VM arguments. -
Thanks for the memory – Understanding how the JVM uses native memory on Windows and Linux
Explains how the memory in the JVM like the heap is memory into the RAM on different operating systems and CPUs (32/64bit). -
Java Micro Edition – Tuning
Describes runtime options to adjust performance in the Java ME edition. It also illustrates the compilation of bytecode into native code. - Summary of Sun’s document “Tuning Garbage collection with the 1.4.2 Hotspot JVM”.
- Discussion about where references and objects are stored in the JVM.
最後更新:2017-05-22 16:37:31