内存溢出与内存泄漏的区别,如何产生的?(JAVA向)
契子:
在我们日常敲代码的时候,肯定都听说过内存溢出和内存泄漏,那为什么会产生内存溢出和内存泄漏呢?今天我们就来了解一下。
一、Java是如何管理内存的
这个就涉及到Java的内存管理模型,我在这里简单的说一下。
在Java中内存分配是有管理员去分配,而回收的话是由GC(垃圾管理机制)去回收,但是这样有利也有弊。好的方面是减少程序员的工作量,而坏的一面是加大的Jvm的工作量。GC它也是一个线程,GC为了正确、及时的释放不再被引用的对象,它需要对每个线程的运行状态、引用、赋值等都需要进行监控。
二、内存泄漏(Memory Leak)
是指程序中动态分配的堆内存由于某种原因未释放或者无法释放,造成的程序运行速度变慢和崩溃等后果。
1、根本原因:
是两个对象的生命周期不一致。
我在这举一个小栗子,方便大家理解:
小明在一天傍晚牵着他个宠物狗去散步,然后突然雷声大作,阴风四起,下起了雨,街上的人都回了家。一个爱狗人士想带着小明的狗去避雨,由于狗脖子上的链子在小明手中,狗无法避雨,只能和小明一起淋雨,最后导致小明和狗都感冒了。
从这个例子可以看出,小明就是生命周期长的,狗就是生命周期短的,由于长的“牵”着短的,导致无法回收,最后都生病起了,也导致了程序变慢或崩溃。
在此再总结一下:生命周期长的对象持有生命周期较短的对象的引用。
2、在日常编码过程会造成的原因
非静态内部类默示持有外部类的引用;
单例模式会造成内存泄漏;
非静态内部类;
外部类持有非静态内部类的静态对象;
Handler 或 Runnable 作为非静态内部类;
BraodcastReceiver 未取消注册,InputStream 未关闭等。
3、如何避免或者解决
最好的方法就是不写代码,不写就没有泄露。
最简单直接的方法,就是使用leakcanary了,给自己的项目加上工具,只要有泄露就会有提示。 性能优化工具leakcanary
修改内存,直接增加内存;
检查错误日志,查看OOM之前是否还有其他的错误。
对代码进行走查和分析
三、内存溢出(Out Of Memory)
通俗理解就是内存不够,是指系统中存在中无法回收的内存或者使用的内存过多,最终使程序运行大于能提供的最大内存。
虚拟机栈主要是服务于Java方法的,一个线程就是一个栈,每一个方法从调用到完成,对应的就是一个栈帧从入栈到出栈的过程。然而当我们请求的线程的深度超过了栈的深度,就会抛出StackOverFlowError错误。但是一般栈的深度是固定的,也可以动态扩展,但是如果申请时,没有得到足够的内存会抛出OutOfMemory错误。
1、造成的原因:
- 内存中加载的数据过于庞大,如一次从数据库中取出多个数据;
- 集合类中有对象的引用,使用后未对其进行清空,使JVM无法回收;
- 代码中存在死循环或循环产生过多重复的对象实体;
- 使用第三方的软件的中BUG;
- 内存设置过小。
2、解决策略:
- 修改内存,直接增加内存
- 检查错误日志,查看OOM之前是否还有其他的错误。
- 对代码进行走查和分析
- 使用内存查看工具动态查看内存使用情况
四、总结
内存泄漏是堆中的存在无用但可达的对象,GC无法回收。
内存溢出是空间不足的溢出,主要分为PermGen space不足、堆不足、栈不足。
内存泄漏的堆积最终会导致内存溢出