1、Java 堆溢出
下面的程中我們限制Java 堆的大小爲20MB,不可擴展(將堆的最小值-Xms 參
數與最大值-Xmx 參數設置爲一樣即可避免堆自動擴展),通過參數-XX:+HeapDump
OnOutOfMemoryError 可以讓虛擬機在出現內存溢出異常時Dump 出當前的內存堆轉儲
快照以便事後進行分析。
參數設置如下
package com.yhj.jvm.memory.heap;
import java.util.ArrayList;
import java.util.List;
/**
* @Described:堆溢出測試
* @VM args:-verbose:gc -Xms20M -Xmx20M -XX:+PrintGCDetails
* @author YHJ create at 2011-11-12 下午07:52:22
* @FileNmae com.yhj.jvm.memory.heap.HeapOutOfMemory.java
*/
public class HeapOutOfMemory {
/**
* @param args
* @Author YHJ create at 2011-11-12 下午07:52:18
*/
public static void main(String[] args) {
List<TestCase> cases = new ArrayList<TestCase>();
while(true){
cases.add(new TestCase());
}
}
}
/**
* @Described:測試用例
* @author YHJ create at 2011-11-12 下午07:55:50
* @FileNmae com.yhj.jvm.memory.heap.HeapOutOfMemory.java
*/
class TestCase{
}
存溢出時,異常堆棧信息“java.lang.OutOfMemoryError”會跟着進一步提示“Java heap
space”。
要解決這個區域的異常,一般的手段是首先通過內存映像分析工具(如Eclipse
Memory Analyzer)對dump 出來的堆轉儲快照進行分析,重點是確認內存中的對象是
否是必要的,也就是要先分清楚到底是出現了內存泄漏(Memory Leak)還是內存溢
出(Memory Overflow)。圖2-5 顯示了使用Eclipse Memory Analyzer 打開的堆轉儲快
照文件。
如果是內存泄漏,可進一步通過工具查看泄漏對象到GC Roots 的引用鏈。於是就
能找到泄漏對象是通過怎樣的路徑與GC Roots 相關聯並導致垃圾收集器無法自動回收
它們的。掌握了泄漏對象的類型信息,以及GC Roots 引用鏈的信息,就可以比較準確
地定位出泄漏代碼的位置。
如果不存在泄漏,換句話說就是內存中的對象確實都還必須存活着,那就應當檢查
虛擬機的堆參數(-Xmx 與-Xms),與機器物理內存對比看是否還可以調大,從代碼上
檢查是否存在某些對象生命週期過長、持有狀態時間過長的情況,嘗試減少程序運行期
的內存消耗。
以上是處理Java 堆內存問題的簡略思路,處理這些問題所需要的知識、工具與經驗
在後面的幾次分享中我會做一些額外的分析。
2、java棧溢出
package com.yhj.jvm.memory.stack;
/**
* @Described:棧層級不足探究
* @VM args:-Xss128k
* @author YHJ create at 2011-11-12 下午08:19:28
* @FileNmae com.yhj.jvm.memory.stack.StackOverFlow.java
*/
public class StackOverFlow {
private int i ;
public void plus() {
i++;
plus();
}
/**
* @param args
* @Author YHJ create at 2011-11-12 下午08:19:21
*/
public static void main(String[] args) {
StackOverFlow stackOverFlow = new StackOverFlow();
try {
stackOverFlow.plus();
} catch (Exception e) {
System.out.println("Exception:stack length:"+stackOverFlow.i);
e.printStackTrace();
} catch (Error e) {
System.out.println("Error:stack length:"+stackOverFlow.i);
e.printStackTrace();
}
}
}
3、常量池溢出(常量池都有哪些信息,我們在後續的JVM類文件結構中詳細描述)
package com.yhj.jvm.memory.constant;
import java.util.ArrayList;
import java.util.List;
/**
* @Described:常量池內存溢出探究
* @VM args : -XX:PermSize=10M -XX:MaxPermSize=10M
* @author YHJ create at 2011-10-30 下午04:28:30
* @FileNmae com.yhj.jvm.memory.constant.ConstantOutOfMemory.java
*/
public class ConstantOutOfMemory {
/**
* @param args
* @throws Exception
* @Author YHJ create at 2011-10-30 下午04:28:25
*/
public static void main(String[] args) throws Exception {
try {
List<String> strings = new ArrayList<String>();
int i = 0;
while(true){
strings.add(String.valueOf(i++).intern());
}
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
4、方法去溢出
package com.yhj.jvm.memory.methodArea;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* @Described:方法區溢出測試
* 使用技術 CBlib
* @VM args : -XX:PermSize=10M -XX:MaxPermSize=10M
* @author YHJ create at 2011-11-12 下午08:47:55
* @FileNmae com.yhj.jvm.memory.methodArea.MethodAreaOutOfMemory.java
*/
public class MethodAreaOutOfMemory {
/**
* @param args
* @Author YHJ create at 2011-11-12 下午08:47:51
*/
public static void main(String[] args) {
while(true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TestCase.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
return arg3.invokeSuper(arg0, arg2);
}
});
enhancer.create();
}
}
}
/**
* @Described:測試用例
* @author YHJ create at 2011-11-12 下午08:53:09
* @FileNmae com.yhj.jvm.memory.methodArea.MethodAreaOutOfMemory.java
*/
class TestCase{
}
5、直接內存溢出
package com.yhj.jvm.memory.directoryMemory;
import java.lang.reflect.Field;
import sun.misc.Unsafe;
/**
* @Described:直接內存溢出測試
* @VM args: -Xmx20M -XX:MaxDirectMemorySize=10M
* @author YHJ create at 2011-11-12 下午09:06:10
* @FileNmae com.yhj.jvm.memory.directoryMemory.DirectoryMemoryOutOfmemory.java
*/
public class DirectoryMemoryOutOfmemory {
private static final int ONE_MB = 1024*1024;
private static int count = 1;
/**
* @param args
* @Author YHJ create at 2011-11-12 下午09:05:54
*/
public static void main(String[] args) {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
while (true) {
unsafe.allocateMemory(ONE_MB);
count++;
}
} catch (Exception e) {
System.out.println("Exception:instance created "+count);
e.printStackTrace();
} catch (Error e) {
System.out.println("Error:instance created "+count);
e.printStackTrace();
}
}
}