JAVA的内存模型及结构
原文链接 译文链接 作者:Tai Truong 译者:Jaxon
所有的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,都存在在堆中。为了更好的理解上面这段话,我们可以看一个例子:
[code lang=”java”]
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.log4j.Logger;
public class HelloWorld {
private static Logger LOGGER = Logger.getLogger(HelloWorld.class.getName());
public void sayHello(String message) {
SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.YYYY");
String today = formatter.format(new Date());
LOGGER.info(today + ": " + message);
}
}
[/code]
这段程序的数据在内存中的存放如下:
通过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.
原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: JAVA的内存模型及结构
发现一个笔误
Exception in thread “main”: java.lang.OutOfMemoryError: PermGen space
原因:类或者方法不能被加载到【【老年代】】。它可能出现在一个程序加载很多类的时候,比如引用了很多第三方的库;
静态变量不是保存在方法区吗? 为什么在堆中 会有 Object LOGGER ?
是LOGGER引用的对象实例,对象实例总是会在heap上产生的,LOGGER这个引用本身应该是在native area中创建
写错了,应该是在method area 😛