深入理解Java虚拟机---(3)内存溢出与内存泄漏

写在前面:

    内存溢出和内存泄漏都是程序中,我们要极力避免出现的异常,二者在字面上看上去相似,但实际上是不一样的异常情况,在这篇博客中,我们会总结内存溢出与内存泄漏的区别。

内存溢出和内存泄漏的定义:

    内存溢出:Out Of Memory,指程序在申请内存时,没有足够的内存空间供其使用。

    内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间。

    用通俗一点的话来解释,内存溢出类似于数组索引越界,超出了数组存储的上限。内存泄漏是指内存使用完毕后,不能释放内存,并回收使用。

内存溢出和内存泄漏所导致的结果:

    内存溢出时,程序将会终止,并且抛出Java.lang.OutOfMemoryError异常

    内存泄漏时,程序并不会立刻终止,但是效率会降低,直到没有剩余内存,最终也会导致内存溢出。

内存溢出的类型:

    (1)Java堆溢出

    Java堆用于存储堆实例,不断的创建对象,那么在对象数量到达最大堆限制时,就会产生内存溢出。

    (2)虚拟机栈和本地方法栈溢出

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

public class JavaVMStackSOF {
		private int stackLength = 1;

		public void stackLeak() {
			stackLength++;// 累加变量
			stackLeak();// 调用自身
		}
	}

    上述代码是在单线程中调试,程序会报
StackOverflowError 异常。 而如果是于多线程之中,程序不断增加线程,并且为每一个线程扩大内存,则会报OutOfMemoryError异常。

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

    运行时常量池是方法区的一部分。方法区用于存放的Class信息,如类名,访问修饰符,常量池,字段描述,方法描述等。

    对于非-常量池部分,运行时生成大量的动态类填满方法区。

    对于常量池部分,如果无限循环调用String的intern()方法产生不同的String对象实例,并在List中保存其引用,以防止被GC回收,最终会产生内存溢出。

    (4)本机直接内存溢出

    而此类内存溢出一个明显的特征是在Heap Dump文件中不会看见明显的异常,如果发现OOM之后Dump文件很小,而程序中又直接或间接使用了NIO,可以考虑一下是不是这方面原因。 

    注:在JDK1.4之后加入了NIO,引入了一种基于通道与缓冲区的I/O方式。

    

    原文作者:java虚拟机
    原文地址: https://blog.csdn.net/May_3/article/details/79515523
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞