我是靠谱客的博主 勤劳镜子,最近开发中收集的这篇文章主要介绍OutOfMemory (OOM)的类型与检测,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Java堆溢出

Java堆存的是对象的实例,所以无限添加对象实例很容易造成堆溢出

public class OutOfMemoryError_Heap {
    static class OOMObject{}
    public static void main(String[] args) {
        List <OOMObject> list = new ArrayList<OOMObject>();
        while(true) {
            list.add(new OOMObject());
        }
    }
}

添加虚拟机参数
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/Users/jj/Desktop
a)Xms20m 堆最小值
b)Xmx20m 堆最大值
c)HeapDumpOnOutOfMemoryError 内存堆转储快照
d)XX:HeapDumpPath=/Users/jj/Desktop 快照存放地址

结果:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to /Users/jj/Desktop/java_pid584.hprof ...
Heap dump file created [27568513 bytes in 0.137 secs

使用MAT内存分析工具分析生成的快照可以看到
这里写图片描述
Shallow Heap是指对象本身占有的内存大小。
Retained Heap是指对象本身加上它引用的对象的大小。
这里OOMObject 的Shadow Heap和Retained Head相同的原因是OOMObject没有引用;而他是16的原因是对象头在64位机器上占有64bit,也就是16个字节,但是由于虚拟机自动使用压缩指针,所以占有12个字节,但是又由于对象占有的内存必须为8的倍数,所以最后结果是16字节。
字节长度计算的方式是 12+类型长度和->最接近8倍数的数字->结果

虚拟机栈和本地方法溢出

栈内存太小和已使用的栈空间太多都会导致虚拟机栈或本地方法溢出。

a)栈溢出


public class JavaVMSStack {
    private int stackLength =1 ;

    public void JavaVMSStack() {
        stackLength ++ ;
        JavaVMSStack();
    }
    public static void main(String[] args) {
        JavaVMSStack j = new JavaVMSStack();
        try {
            j.JavaVMSStack();
        } catch (Exception e) {
            System.out.println(j.stackLength);
            throw e;
        }
    }
}

虚拟机参数
-Xss160k

这里写图片描述

b)内存溢出

我们知道,虚拟机会为每个线程的栈先分配一段可以调整的内存,每个线程分配到的栈帧越大,可以建立的线程就越少,建立线程时就越容易把剩下的内存耗尽。


public class JavaVMSStackOOM {
    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) {
        JavaVMSStackOOM oom = new JavaVMSStackOOM();
        oom.stackLeakByThread();
    }
}

虚拟机参数:

-vss20M

在Windows平台的虚拟机中,Java的线程是映射到虚拟机的内核上的,隐私上述代码执行时有较大的风险,可能会导致系统假死。

方法区和运行时常量池溢出

运行时常量池是方法区的一部分。
在jdk1.6以前,由于常量池位于永久代中,而我们可以通过参数去限制方法区的大小,所以间接影响到常量池的容量。
而jdk1.7以后, 已经把原本放在永久代的字符串常量池移出, 放在Java堆中(元空间Metaspace)中,元数据并不在虚拟机中,使用的是本地的内存。

可以通过以下参数来指定元空间的大小:
  
  -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。

 -XX:MaxMetaspaceSize,最大空间,默认是没有限制的。

最后

以上就是勤劳镜子为你收集整理的OutOfMemory (OOM)的类型与检测的全部内容,希望文章能够帮你解决OutOfMemory (OOM)的类型与检测所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(83)

评论列表共有 0 条评论

立即
投稿
返回
顶部