内存泄漏和内存溢出--原因和解决方法

一,内存泄漏

内存泄漏memory leak :是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出

二,内存溢出

内存溢出 out of memory :指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出

三,两者的关系

  • 内存泄漏的堆积最终会导致内存溢出。内存溢出就是你要的内存空间超过了系统实际分配给你的空间,此时系统相当于没法满足你的需求,就会报内存溢出的错误。
  • 内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。
  • 内存溢出:一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出。比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出。

四,内存泄漏的分类(按生产方式分类)

⭐ 1)常发性内存泄漏:发生内存泄漏的代码会被多次执行到,每次执行都会导致一块内存泄漏。
⭐2)偶发性内存泄漏:发生内存泄漏的代码只会在某些特定环境或操作过程下才会执行。
常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
复制代码
⭐3)一次性内存泄漏:发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
⭐4)隐式内存泄漏:程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。

五,内存溢出的原因及解决方法

内存溢出原因:

1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
3.代码中存在死循环或循环产生过多重复的对象实体;
4.使用的第三方软件中的BUG;
5.启动参数内存值设定的过小。

内存溢出解决方案:

第一步、修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加)
第二步、检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。
第三步、对代码进行走查和分析,找出可能发生内存溢出的位置。

六,内存泄漏的原因以及解决方案

内存泄漏的原因归根到底就是当需要被回收变量的内存被其他变量引用持有,导致内存回收失败
常见的原因有:
1.非静态内部类/匿名类

原因1*:非静态内部类/匿名类 Handler持有外部的Activity/Fragment对象的引用,导致Activity/Fragemnt被销毁的时候没有被回收
解决方案:
将Handler类改为静态内部类 + 弱引用(WeakReference)持有Activity引用(静态类默认不持有外部的引用)
当外部类(一般是Activity/Fragment)结束生命周期时,清空Handler队列

原因2:非静态内部类的实例(对象) = 静态实例 (其生命周期 = 应用的生命周期)
解决方案:
将该类改为静态类(静态类默认不持有外部的引用)
将该类抽出来封装成为一个单例

原因3:多线程 工作线程正在处理任务时外部类需要销毁,此时工作线程持有外部类的引用导致无法被回收
解决方案:
将该线程类类改为静态类(静态类默认不持有外部的引用)
当外部类结束生命周期时强制结束线程

2.集合类

原因:集合类添加元素之后持有集合元素的引用,导致该集合元素不可被回收,导致内存泄漏
解决方案
集合类使用完元素对象后,必须将该元素从集合中删除(由于一个集合中有多个元素,所以最简单的方案就是清空集合对象(clean)&设置为Null)

3.资源对象使用后未关闭

原因:资源对象使用后未关闭,在Activity/Fragemnt销毁时没有关闭/注销这些资源,将导致无法回收 例如:广播BraodcastReceiver、文件流Fire、图片资源Bitmap、数据库游标等
解决方案
Activity销毁时及时关闭/注销资源

4.Static关键字修饰成员变量

原因:Static关键字修饰成员变量的生命周期 = 应用的生命周期 例如 private static Context mContext = context 那么context上下文对应的Activity则无法被回收
解决方案
尽量不要使用Static成员变量引用,使用弱引用代替强引用
使用单例模式

你可能感兴趣的:(JavaEE进阶,java,jvm)