Java堆溢出及栈溢出

内存溢出Out Of Memory(OOM):指申请内存时,没有足够的内存供其使用。

内存泄露Memory Leak:内存泄露,程序申请内存后,无法释放已申请的内存空间。内存泄露的堆积,浪费了内存空间,可能会造成OOM.

堆溢出信息: OutOfMemoryError : Java heap space

分析工具:Eclipse Memory Analyzer


栈溢出

HotSpot VM并不区分虚拟机栈和本地方法栈,所以 -Xoss参数(设置本地方法栈大小)在HotSpot无效,只能通过-Xss参数设置栈容量。

  1. 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
  2. 如果虚拟机在扩展栈时无法申请到足够的空间,抛出OutOfMemoryError异常。

本质上是同一件事。

经过验证——在单线程的情况下,无论是栈帧太大还是虚拟机容量太小,当内存无法分配是,抛出的都是StackOverflowError异常。

分配给栈的内存并不是越大越好,因为栈内存越大,线程多,留给堆的空间就不多了,容易抛出OOM。JVM的默认参数一般情况没有问题(包括递归)。


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

运行时常量池是方法区的一部分。

String.intern()是Native方法。

    1.8实测
        String sb1 = new StringBuilder("计算机").append("软件").toString();
        System.out.println(sb1.intern() == sb1);

        String string = new StringBuilder("Ja").append("va").toString();
        System.out.println(string.intern() == string);
        
        true
        false

1.6之前执行intern()会把首次遇到的字符串实例复制到永久代,返回的也是永久代这个实例的引用,而StringBuilder实例在Java堆上,必然不是同一个引用,将返回false。

1.7之后intern()不会再复制实例,只是在常量池中记录首次出现的实例引用,因此intern返回的引用和由StringBuilder创建的那个字符实例是同一个。由于java这个字符串常量池已经有了,所以intern返回的是常量池的引用,与string并不相等。

方法区溢出:常见的内存溢出,一个类要被垃圾收集器回收掉,条件比较苛刻。在经常动态生成大量Class的应用中,需要特别注意。


本机内存直接溢出

-XX:MaxDirectMemorySize 指定DirectMemory,如果不指定,默认与Java最大值(-Xmx)一样。
由DirectMemory导致的内存溢出,Heap Dump文件不会看到明显的异常,如果OOM之后Dump文件很小,而程序又直接使用了NIO,就要考虑是否是Direct Memory溢出了。

猜你喜欢

转载自blog.csdn.net/qq_33423418/article/details/82834432