JVM抛出OutOfMemory 的集中情况的解析

1、java堆的内存泄露和内存溢出

内存泄露:一个生命周期长的对象引用一个生命周期短的对象,当生命周期短的对象不再被使用时,不能被GC进行回收。

内存溢出:对象的生命周期长,一直占用内存,新的对象无法再被创建,就会抛出OutOfMemoryError的异常。

/**
 * VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapOOM {


static class OOMObject {
}


public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();


while (true) {
list.add(new OOMObject());
}
}
}

这就是一个内存溢出的例子。可以使用Memory Analyzer进行解析。设置虚拟机的最大内存 -Xmx20m 最小内存-Xms20m  以及生成Heap文件用于分析的指令-XX:+HeapDumpOnOutOfMemoryError

2:jvm栈和本地方法栈的溢出造成的StackOverFlowError以及OutOFMemoryError异常

通过设置-Xss128k设置JVM的一个线程的栈的大小是128K,当方法中的变量超过这个限制的时候,就会抛出异常例如:

package outofmemory;
/**
 * VM Args:-Xss128k
 */
public class JavaVMStackSOF {


private int stackLength = 1;


public void stackLeak() {
stackLength++;
stackLeak();
}


public static void main(String[] args) throws Throwable {
JavaVMStackSOF oom = new JavaVMStackSOF();
try {
oom.stackLeak();
} catch (Throwable e) {
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}

抛出异常的原因:由于不断的递归,栈的容量不断被使用直到不能再被分配空间,就会抛出StackOverFlowError的异常。这个是在单线程的情况下

对于多个线程来说,当java的堆和方法区的共享内存是固定时,程序计数器的内存是可以忽略的,如果每个线程的栈很大,则线程就会很少,如果适当的减少栈的容量

则JVM可以创建更多的线程接受用户的请求。所以有的时候,为了JVM能创建更多的线程,我们需要减少堆和栈的容量。

多个线程创建引发的异常如下 java.lang.OutOfMemoryError: unable to create new native thread

package outofmemory;
/**
 * VM Args:-Xss2M 
 */
public class JavaVMStackOOM {
 
       private void dontStop() {
              while (true) {
              }
       }
 
       public void stackLeakByThread() {
              while (true) {
                     Thread thread = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                   dontStop();
                            }
                     });
                     thread.start();
              }
       }
 
       public static void main(String[] args) throws Throwable {
              JavaVMStackOOM oom = new JavaVMStackOOM();
              oom.stackLeakByThread();
       }
}

3:方法区和运行时常量池抛出的OutOfMemoryError异常的情况

方法区主要负责类的加载存储,运行时常量池主要存储常量和符号引用,如果在程序运行期间不断的向常量池加入值,超出常量池的大小就会抛出异常。例如:
package outofmemory;
import java.util.ArrayList;
import java.util.List;
/**
 * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M
 */
public class RuntimeConstantPoolOOM {
public static void main(String[] args) {
// 使用List保持着常量池引用,避免Full GC回收常量池行为
List<String> list = new ArrayList<String>();
// 10MB的PermSize在integer范围内足够产生OOM了
int i = 0; 
while (true) {
list.add(String.valueOf(i++).intern());
}
}
}

将方法区的大小设置为最小值-XX:PermSize=10M 最大值 -XX:MaxPermSize=10M 加快异常的抛出

因为String.intern()在程序运行的时候,将字符串不断的加入运行时常量池中

抛出java.lang.OutOfMemoryError: PermGen space

介绍一下String.intern()方法,如果常量池中有这个值则直接取出,若没有,则将值放入到常量池中。

4、本机内存溢出

/**
 * VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M
 */
public class DirectMemoryOOM {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) throws Exception {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true) {
unsafe.allocateMemory(_1MB);
}
}
}
如果使用NIO来进行操作,可能造成本地的内存溢出




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值