堆内存溢出
eclipse设置
-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
run configuration设置
-verbose:gc -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
代码如下:
public class JvmTest {
static class OOMObject{
}
public static void main(String[] args) {
// TODO Auto-generated method stub
List<OOMObject> list = new ArrayList<OOMObject>();
while(true) {
list.add(new OOMObject());
}
}
}
结果:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid10052.hprof ...
Heap dump file created [27957091 bytes in 0.078 secs]
解决方法:
使用内存映像分析工具(如:eclipse memory analyzer)对Dump出来的堆转储快照进行分析。
如果是内存泄漏,查看是哪个本应当被回收的对象没有被回收,通过工具查看GC Root引用链。
如果是内存溢出,那么就检查虚拟机堆参数设置(-Xms,-Xmx)
虚拟机栈溢出和本地方法栈溢出
HotSpot栈大小由-Xss设定(因为它不区分虚拟机栈和本地方法栈)
run configuration设置
-verbose:gc -Xss128k
代码如下:
public class JvmTest {
private int stackLength = 1;
public void stackLeak() {
stackLength++;
stackLeak();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
JvmTest oom = new JvmTest();
try {
oom.stackLeak();
}catch (Throwable e) {
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}
创建线程导致内存溢出异常
设置:
-verbose:gc -Xss2M
代码
public class JvmTest {
private void dontStop() {
while(true) {
}
}
public void stackLeakByThread() {
while(true) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
JvmTest oom = new JvmTest();
oom.stackLeakByThread();
}
}
这个代码容易让操作系统假死,因为在windows平台的虚拟机上,Java的线程直接映射到操作系统的内核线程上,无限的创建会让操作系统压力很大。
结果:
unable to create native thread
方法区和运行时常量池溢出
运行时常量池导致的内存溢出异常
设置:
-verbose:gc -XX:PermSize=6M -XX:MaxPermSize=6M -Xmx6M
代码:
public class JvmTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Set<String> set = new HashSet<String>();
short i = 0;
while(true) {
set.add(String.valueOf(i++).intern());
}
}
}
因为jdk7或更高版本把原本存放在永久代的字符串常量池移到了java堆中所以要使用-Xmx限制最大堆。
显示异常:
[GC (Allocation Failure) 1024K->848K(5632K), 0.0019114 secs]
[GC (Allocation Failure) 1872K->1792K(5632K), 0.0048692 secs]
[GC (Allocation Failure) 2735K->2736K(5632K), 0.0027380 secs]
[GC (Allocation Failure) 3760K->3648K(5632K), 0.0030725 secs]
[Full GC (Ergonomics) 3648K->3572K(5632K), 0.2101547 secs]
[Full GC (Ergonomics) 4596K->4595K(5632K), 0.0273795 secs]
[Full GC (Ergonomics) 4921K->4918K(5632K), 0.0171513 secs]
[Full GC (Allocation Failure) 4918K->4906K(5632K), 0.0398508 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.HashMap.resize(HashMap.java:704)
at java.util.HashMap.putVal(HashMap.java:663)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
at MMemory.JvmTest.main(JvmTest.java:36)
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=6M; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=6M; support was removed in 8.0
借助CGlib使方法区出现内存溢出异常
-verbose:gc -XX:PermSize=10M -XX:MaxPermSize=10M
由于书中没有给出CGlib的版本,这段代码运行问题挺多的,以后再写。
JDK8之后,元空间代替了永久代。
涉及参数:
元空间最大值
-XX:MaxMetaspaceSize
元空间初始大小
-XX:MetaspaceSize
垃圾收集之后控制最小元空间剩余容量的百分比
-XX:MinMetaspaceFreeRatio
本机直接内存溢出
参数
-verbose:gc -Xmx20M -XX:MaxDirectMemorySize=10M
书中代码使用到了Unsafe类,这个类据说是在jdk6之后被移除,我在写代码的时候,发现import失败,在网上查,说不建议用这个包。