JVM——内存泄漏与内存溢出

1.内存溢出:squirrel:

1.1 什么是Java的内存溢出?

在Java程序运行的过程中,经常会碰到以下错误:java.lang.OutOfMemoryError
通俗讲,内存溢出是指程序在申请内存时,没有足够的内存空间供其使用,出现OutOfMemoryError。

1.2 产生原因?

简单来讲为以下两点:
1. JVM内存过小
2. 产生过多的,没有被回收的垃圾

以下讨论主要基于JVM上不同内存区域的讨论

1.3 Java堆溢出

Java堆是存放对象实例的地方,当我们不断申请创建对象,并且保证这些对象始终可以从GC Roots可达,总容量就会触及最大堆的容量限制而抛出内存溢出异常
例如以下代码,将虚拟机的初始大小设为 20M ,并且不可变(将堆的最小值 -Xms 和 堆的最大值 -Xmx 设置为一样可以避免Java堆自动扩展!

public class OOM {
    /*
        -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError 
    */
    static class OOMObject{

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

JVM——内存泄漏与内存溢出

解决方法:boom:

常规处理方法是通过内存映像分析工具对 Dump 出来的堆转储快照进行分析。
1.首先分析是内存泄漏还是内存溢出
2.如果是内存泄漏通过工具查看泄露对象到 GC Roots 的引用链,分析垃圾收集器无法回收他们的原因,进而定位到出现问题的代码
3.如果不是内存泄漏,即对象都应该必须活着,就应该对比 JVM堆内存 和机器内存相比是否还有向上调整的空间;或者从代码上检查某些对象是否生命周期过长,持有状态时间过长,存储结构设计不合理等,尽量减少程序运行期间的内存消耗

1.4 虚拟机栈和本地方法栈溢出

1. 如果线程请求栈的深度大于虚拟机所允许的最大深度,将抛出 StackOverflowError 异常

2. 如果虚拟机的栈内存允许动态的扩展,当扩展栈的容量无法申请到足够的内存的时候,将抛出’OutOfMemoryError’异常

解决方法:boom:

1.出现 StackOverflowError 异常时,会有明确错误堆栈可供分析,比较容易定位问题所在,例如递归没有终止条件。栈深度大多数情况下到达1000-2000是没有问题的,对于正常方法的调用,这个深度完全是够用的。
2.但如果是因为建立过多线程导致内存溢出,在不能减少线程的数量的情况下,只能通过减少最大堆的容量或者减少栈的容量来获取更多的线程!

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

由于在JDK 8 以后,永久代退出了历史舞台,元空间作为其替代者登场,即元空间使用的是直接内存,受限于本机物理内存的大小,不再容易抛出方法区的内存溢出。而在JDK 8 之前,方法区的实现永久代是会因为加载了大量的类(比如CG Lib字节码技术)而抛出方法区内存溢出的,或者因为运行时常量池(JDK 6 还是属于方法区的一部分,抛出的是方法区的内存溢出;而JDK7之后便移到Java堆上,抛出的是java的堆内存溢出)而抛出对应区域的内存溢出!

1.6 本机直接内存溢出

直接内存可以通过 -XX:MaxDirectMemorySize 参数来指定,若不指定则默认与堆的最大值保持一致。
由直接内存导致的内存溢出,一个明显的特征就是在dump下的文件不会看到有明显的异常情况,或者该文件很小,而程序又直接或者间接的使用了 Direct Memory ,就应该去考虑是否是本机直接内存溢出

2. 内存泄漏:squirrel:

Memory Leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点:

  1. 首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;
  2. 其次,这些对象是无用的,即程序以后不会再使用这些对象。

如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。

3.两者联系

内存泄露会最终会导致内存溢出。
相同点:都会导致应用程序运行出现问题,性能下降或挂起。
不同点:
1. 内存泄露是导致内存溢出的原因之一,内存泄露积累起来将导致内存溢出。
1. 内存泄露可以通过完善代码来避免,内存溢出可以通过调整配置来减少发生频率,但无法彻底避免。

JVM
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!