@xtccc
2016-06-16T20:15:35.000000Z
字数 3522
阅读 2921
Java
参考:
大体上看,JVM的内存空间可以划分为两类:
所有threads都可以访问的空间,可以分为两类:1) Method Area; 2) Heap ;
Class loader将加载一个class的字节码,并将其传递给JVM。Method area负责存储class相关的信息,包括以下数据区域:
不必对Method area中的空间进行GC。
Heap管理着所有的class实例(对象)及数组,JVM标准要求必须有GC机制对heap中的对象进行回收。
Heap可以被划分为两种generations:young generation(new generation)
和 old generation(tenured generation)
而Method Area则被划分为另一种generation:permenant generation
Young generation 也可以被称为 new generation,它可以被进一步分为3个区域:Eden, Survivor Space I,以及 Survivor Space II。
当JVM创建一个对象时,它首先出现在 Eden,然后被移动至 Survivor I,然后再被移动至 Survivor II,最后被移动至 Old generation。
在 Minor GC 期间,JVM会将对象移动至young generation的各区域。
在GC时,如果old generation中没有足够的空间容纳对象,JVM会触发 Major GC 进程,这会对所有的Java App在性能上造成较大的负面影响。
我们可以告诉JVM应该将young generation和old generation的大小设置为多少字节,但是这只作为hint,真正的size仍然由JVM自己计算决定。参数 -XX:NewSize
可以设置young generation的初始大小,同时参数 -XX:NewRatio
可以设置 old generation 与 young generation 的size比例。例如,如果 -XX:NewRatio 设置为2,那么old generation的大小将是yound generation的大小的2倍。
对象(objects)在heap中产生,且只要被引用,它们就是存活的(live)。在GC期间,gargabe collector会检查这些objects是否处于被引用的状态,如果不是的话,则会将其标记为“garbage”,并且随后清理这些objects。
这是一类特殊的objects,它们不会被任何人引用,参考 GC roots。如果一个object本身不是GC root,也没有被GC root直接或间接引用,则它就将被garbage collector收集并清理。
有三类GC roos:
下面是一个例子
public class MyFrame extends javax.swing.JFrame {
// reachable via Classloader as soon as this class is loaded
public static final ArrayList STATIC = new ArrayList();
// as long as the JFrame is not dispose()'d,
// it is reachable via a native window
private final ArrayList jni = new ArrayList()
// while this method is executing
// the parameter is kept reachable,
// even if it is not used
private void myMethod(ArrayList parameter) {
// while this method is running,
// this list is reachable from the stack
ArrayList local = new ArrayList();
}
}
OutOfMemoryError 异常可以发生在任意内存区域。
如果Garbage Collector无法为一个新的对象分配内存空间,就会抛出如下的异常 :
Exception in thread "main": java.lang.OutOfMemoryError: Java heap space
如果试图在heap中分配一个超过了total heap size的array,则会抛出以下异常:
Exception in thread "main": java.lang.OutOfMemoryError: Requested array size exceeds VM limit
如果method area没有足够的空间来创建一个新的class,则会抛出以下异常:
Exception in thread "main": java.lang.OutOfMemoryError: PermGen space
OutOfMemoryError 也可以发生在哪些只能由某个thread访问的区域中:
如果JVM中有了太多的methods,没有足够的空间来创建新的method,则会抛出以下异常:
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
如果在native stack(JNI method call)中出现内存分配错误,则会抛出以下异常:
Exception in thread "main": java.lang.OutOfMemoryError: (Native method)
如果OS没有足够的内存(例如其他的进程用完了全部的内存,或者swap space设置得太小),则会抛出以下异常:
Exception in thread "main": java.lang.OutOfMemoryError: request bytes for . Out of swap space?
通常,引发 OutOfMemeoryError 的case有3种:
当某些objects拥有GC root reference,但是Java app的代码不会再使用到这些objects时,就称发生了memory leak,这些无用的objects我们不妨叫它们“loitering objects”,这些 loitering objects 会在JVM的整个生命周期中一直存在。如果Java app不断地产生loitering objects,那么内存空间最终将被耗尽,从而引发 OutOfMemoryError 。
例如,如果我们创建了 static collection,将其用作缓存。我们向该static collection中不断地加入objects(add/append/put),又从不删除这些objects(remove)。由于这些被加入的objects是被static collection引用的,因而它们是不能被GC清理的(因为:通过class loader,static collection拥有了GC root reference)。