内存溢出和内存泄露

54 阅读3分钟

1. 内存溢出

内存溢出(out of memory):是指程序在申请内存时,没有足够的内存空间供其使用,就会出现out of memory。

内存溢出常见场景:

  1. 栈溢出:循环调用自己的方法,不断在栈中压栈。
  2. 堆溢出:在堆中创建了很多对象或存储了很大的数据,造成堆中放满了对象,再次有对象申请时,发现内存不足,就会报oom。
  3. GC回收极限:回收时间过长,每次有98%的时间在回收内存,但只回收了不到2%的内存,多次GC后连续不断回收2%的情况下才会抛出异常。如果没有抛出,那就是GC回收的这点内存又会堆满,迫使GC又进行回收,造成恶性循环,使GC的使用率一直在100%工作,而没有任何效果。

1.1 如何加载Bitmap防止内存溢出

  1. 对图片进行内存压缩
  2. 高分辨率的图片放入对应文件夹
  3. 内存复用
  4. 及时回收

2. 内存泄漏

内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏危害可以忽略,但内存泄漏堆积后果很严重,无论多少内存,迟早被占光。类似于内存上不可用的漏洞。

内存泄漏常见场景:

  1. 创建和应用生命周期一样的单例对象

不正确使用是引起内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄漏。

  1. 创建匿名内部类的静态对象
  2. 未关闭资源
  3. 长时间存在的集合容器中创建生命周期短的对象

2.1 Thread是如何造成内存泄漏的,如何解决?

在主线程里创建了一个thread,里面的run方法里在执行耗时的操作,当thread正在执行时,activity发生了横竖屏切换,那么原来的activity就应该先被销毁再进行创建,可是由于内部类持有外部类的引用,造成了thread在运行时还持有activity的引用,导致activity不能被回收,这时候就会发生内存泄露。

如何解决:

  1. 设置静态内部类
  2. 把持有的外部类改成弱引用,弱引用是当GC回收时,不管内存是否充足,只要发现弱引用的对象就进行回收

2.2 Handler导致的内存泄漏的原因以及如何解决

因为Handler是内部类,如果Handler的Looper和MessageQueue在主线程,那么Handler会持有外部类的引用,如果activity销毁时,Handler还在运行,那么就会造成内存泄漏。

如何解决:

  1. 将它定义成静态的内部类,静态内部类不持有外部类的引用
  2. 把持有的外部类引用改为弱引用,因为有可能需要访问外部类成员