Scavenge GC
一般情况下,当新对象生成,并且在 Eden 申请空间失败时,就会触发 Scavenge GC,对
Eden 区域进行 GC,清除非存活对象,并且把尚且存活的对象移动到 Survivor 区。然后整
理 Survivor 的两个区。这种方式的 GC 是对年轻代的 Eden 区进行,不会影响到年老代。
因为大部分对象都是从 Eden 区开始的,同时 Eden 区不会分配的很大,所以 Eden 区的
GC 会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使 Eden 去能尽快空
闲出来。
Full GC
对整个堆进行整理,包括 Young、Tenured 和 Perm。Full GC 因为需要对整个堆进行回
收,所以比 Scavenge GC 要慢,因此应该尽可能减少 Full GC 的次数。在对 JVM 调优的过
程中,很大一部分工作就是对于 FullGC 的调节。有如下原因可能导致 Full GC:
1.年老代(Tenured)被写满
2.持久代(Perm)被写满
3.System.gc()被显示调用
4.上一次 GC 之后 Heap 的各域分配策略动态变化
五、Java 有了 GC 同样会出现内存泄露问题
1.静态集合类像 HashMap、Vector 等的使用最容易出现内存泄露,这些静态变量的生命周
期和应用程序一致,所有的对象 Object 也不能被释放,因为他们也将一直被 Vector 等应
用着。
Static Vector v = new Vector();
for (int i = 1; i<100; i++)
{
Object o = new Object();
v.add(o);
o = null;
}
在这个例子中,代码栈中存在 Vector 对象的引用 v 和 Object 对象的引用 o 。在 For 循环
中,我们不断的生成新的对象,然后将其添加到 Vector 对象中,之后将 o 引用置空。问
题是当 o 引用被置空后,如果发生 GC,我们创建的 Object 对象是否能够被 GC 回收呢?
答案是否定的。因为, GC 在跟踪代码栈中的引用时,会发现 v 引用,而继续往下跟踪,
就会发现 v 引用指向的内存空间中又存在指向 Object 对象的引用。也就是说尽管 o 引用
已经被置空,但是 Object 对象仍然存在其他的引用,是可以被访问到的,所以 GC 无法将
其释放掉。如果在此循环之后, Object 对象对程序已经没有任何作用,那么我们就认为此
Java 程序发生了内存泄漏。
2.各种连接,数据库连接,网络连接,IO 连接等没有显示调用 close 关闭,不被 GC 回收
导致内存泄露。
3.监听器的使用,在释放对象的同时没有相应删除监听器的时候也可能导致内存泄露。