首页 > 试题广场 >

App运行时发生OOM的原因你知道哪几种?如何避免?

[问答题]

App运行时发生OOM的原因你知道哪几种?如何避免?

1.资源对象没关闭造成的内存泄露,try catch finally中将资源回收放到finally语句可以有效避免OOM。资源性对象比如:

1-1,Cursor
1-2,调用registerReceiver后未调用unregisterReceiver()
1-3,未关闭InputStream/OutputStream
1-4,Bitmap使用后未调用recycle()

 

2.作用域不一样,导致对象不能被垃圾回收器回收,比如:
2-1,非静态内部类会隐式地持有外部类的引用,
2-2,Context泄露
概括一下,避免Context相关的内存泄露,记住以下事情:
   1、 不要保留对Context-Activity长时间的引用(对Activity的引用的时候,必须确保拥有和Activity一样的生命周期)
   2、尝试使用Context-Application来替代Context-Activity 3、如果你不想控制内部类的生命周期,应避免在Activity中使用非静态的内部类,而应该使用静态的内部类,并在其中创建一个对Activity的弱引用。
      这种情况的解决办法是使用一个静态的内部类,其中拥有对外部类的WeakReference。
2-3,Thread 引用其他对象也容易出现对象泄露。
2-4,onReceive方法里执行了太多的操作


3.内存压力过大
  3-1,图片资源加载过多,超过内存使用空间,例如Bitmap 的使用
  3-2,重复创建view,listview应该使用convertview和viewholder

 

如何避免内存泄露:
1.使用缓存技术,比如LruCache、DiskLruCache、对象重复并且频繁调用可以考虑对象池
2.对于引用生命周期不一样的对象,可以用软引用或弱引用SoftReferner WeakReferner
3.对于资源对象 使用finally 强制关闭
4.内存压力过大就要统一的管理内存

发表于 2017-07-24 15:25:21 回复(4)
发表于 2017-11-22 16:47:22 回复(0)
JVM的内存区域大致可以分为Java堆、方法区、虚拟机栈、本地方法栈、程序计数器。除了程序计数器不可能发生OOM之外,其他区域都可能发生OOM。
Java堆:Java堆发生内存溢出,主要是活着的对象占用的空间超过堆空间的大小。避免的方法可以罗列如下:
1.分析是否创建的很多不必要创建的对象;
2.或者是已经应该死掉的对象,没有在正常的声明周期中死掉;
3.或者在前面都正常的情况下,考虑是否可以在成本可以接收的范围内对实现进行重构和优化,避免这种情况;
4.在前面都正常的情况下,查看堆、方法区等等占用内存的比例,看看是否可以调大堆的大小;
5.在前面都正常的情况下,查看物理内存和虚拟机内存的比例,考虑不影响机器上其他应用的前提下,适当加大虚拟机内存;
6.在前面都正常的情况下,考虑适当加大物理机内存。

方法区:方法区是存放Java类文件和运行时常量池的地方,导致OOM也应该主要是这两方面的原因。避免的方法罗列如下:
1.查看是否其他区域的信息是否放到方法区,如果是,考虑是否可以把他们迁出去;
2.分析运行时常量池是否占用内存过多,是否有无必要,就算有必要,是否可以用其他的方式代替,比如在堆中分配;
3.分析不需要的类文件是否过多,是否可以卸载不必要的类文件;
其他的优化方式,类似于Java堆的3.4.5.6,将Java对改成方法区即可。

虚拟机栈:虚拟机栈是Java执行方法的在内存中分配的空间,出现OOM可能有两种情况,栈深度溢出或者因为栈太多导致内存不够(这种情况主要出现在多线征程)。避免的方法罗列如下:
1.栈深度溢出的话,可以考虑加大Java虚拟机栈的大小,如果Java虚拟机栈的空间允许的话;
2.如果由于栈太多,导致OOM,可以考虑适当减小栈的深度(如果可以满足业务需求)来避免;
其他的解决方式可以考虑类似于Java堆的3.4.5.6,将Java对改成虚拟机栈即可。

本地方法栈:本地方法栈是Java虚拟机调用本地方法,所使用的栈空间。解决方法可以罗列如下:
1.考虑优化程序,减少调用本地方法调用的次数,或者加大调用次数减少内存即可;
2.加大物理内存;
3.在某些情况下,也可以考虑调小虚拟机内存,本地方法栈所占的大小。


发表于 2017-08-03 10:45:33 回复(2)
1.资源对象没关闭造成的内存泄露,try catch finally中将资源回收放到finally语句可以有效避免OOM。资源性对象比如: 1-1,Cursor 1-2,调用registerReceiver后未调用unregisterReceiver() 1-3,未关闭InputStream/OutputStream 1-4,Bitmap使用后未调用recycle() 2.作用域不一样,导致对象不能被垃圾回收器回收,比如: 2-1,非静态内部类会隐式地持有外部类的引用, 2-2,Context泄露 概括一下,避免Context相关的内存泄露,记住以下事情:    1、 不要保留对Context-Activity长时间的引用(对Activity的引用的时候,必须确保拥有和Activity一样的生命周期)    2、尝试使用Context-Application来替代Context-Activity 3、如果你不想控制内部类的生命周期,应避免在Activity中使用非静态的内部类,而应该使用静态的内部类,并在其中创建一个对Activity的弱引用。       这种情况的解决办法是使用一个静态的内部类,其中拥有对外部类的WeakReference。 2-3,Thread 引用其他对象也容易出现对象泄露。 2-4,onReceive方法里执行了太多的操作 3.内存压力过大   3-1,图片资源加载过多,超过内存使用空间,例如Bitmap 的
发表于 2019-01-23 13:33:40 回复(0)

1.资源对象用完没有关闭,造成内存泄漏。避免:对于资源性对象,在try catch finally中将资源对象放在finally中进行回收处理,可以有效避免OOM。资源性对象例如:

       1-1:Cursor(使用Curosr.close())

       1-2:  没有关闭InputStream/OutputStream 

       1-3:使用完registerReceiver后没有调用unregisterReceiver

       1-4:   Bitmap使用完后没有调用recycle

2.作用域不一样,导致对象不能被垃圾回收器回收

        2-1:非静态内部类隐式持有外部类的引用

        2-2:Context泄漏:

                  2-2-1:不要保留Context-Activity长时间的引用(使用Context-Activity时必须确保和Activity一样的生命周期)

                  2-2-2:使用Context-Application代替Context-Activity

                  2-2-3:  如果你不想控制内部类的生命周期,应该避免在Activity中使用非静态内部类,应该使用静态内部类,并且在其中创建一个Activity的弱引用(WeakRefrener)

        2-3:Thread中引用其他对象也容易造成内存泄漏

        2-4:OnReceive方法里执行了太多操作

3.内存压力过大

        3-1:图片资源加载过多,超出内存使用空间,例如Bitmap

        3-2:  重复创建View,listview应该复用convertview和viewholder



避免内存泄漏:

 1:使用缓存技术,如LruCache、DisLruCache、对象重复并且频繁调用可以考虑对象池

 2:对于生命周期不一样的对象,可以采用软引用或弱引用(SoftRefrener,WeakRefrener)

 3:  对于资源对象用完后在finally中强制关闭

 4:内存压力过大,就要用统一的内存管理

发表于 2018-09-05 23:24:01 回复(0)
主要有三种:

1. 存在内存泄漏引起 jvm 内存不断增加,直到占用过高超过系统能申请的内存
2. 不存在内存泄漏但由于使用了占用大量内存的资源或代码而引起超过系统能申请的内存
3. 超过系统能申请的最大线程数,也会触发 OOM

对应的避免方式:

1. 管理好内存回收,通过 Eclipse mat 、leakcanary 等调试期框架,线上的 APM 框架来定位泄漏源
2. 通过 Memory profiler、mat 等工具定位内存占用 Retained Size 排行较高的类从而调整对应资源或库的使用方式、复用及时回收机制等。另外如果存在内存抖动也可能是瞬时申请的资源占用内存过大导致了瞬时内存超过限制
3. 通过 memory profiler 或 apm 框架 定位线程增加的主要源,并且优化管理app 内部的线程使用、接管第三方库线程池,机器分级定义线程池数量等方式手段减少线程池
发表于 2020-05-30 11:07:22 回复(0)
DAFADFJLKAJG

发表于 2019-07-18 20:04:23 回复(0)
 
发表于 2019-06-17 14:51:56 回复(0)

发表于 2019-02-21 15:41:17 回复(0)
1. 无限递归
2. 内存泄漏

1. 递归要有正确的 return 条件来中断
2. 正确处理好对象泄漏代码(可用代码分析工具等)
发表于 2018-05-16 18:28:44 回复(0)
  1. 瞬时加载了一些资源,例如,视频、图片、音频等等的内存申请大小超过了App的额定内存值,解决方案:对资源可能需要申请大内存的地方做压缩处理
  2. 数据库cursor没有关闭,解决方案:使用完cursor及时关闭
  3. 构造Adapter没有使用缓存contentview, 解决方案:在构造Adapter的时候,使用ContentView缓存页面,节省内存。
  4. 调用registerRecevier() 后未调用 unregisterReceiver(), 解决方案:在每一次动态注册的时候,记得在在适当的地方(Activity的OnDestory())取消注册
  5. 未关闭InputStream/OutputStream , 解决方案:在使用到IO Stream 的时候,及时关闭。
  6. Bitmap使用后未调用recycle() ,解决方案:在Bitmap不在需要被加载到内存中的收获,做回收处理。
  7. Context泄露,内部类持有外部类的引用。 解决方案:  第一: 将线程的内部类,改为静态内部类  第二:在线程内部采用弱引用保存Context引用。
  8. static 原因。 解决方案: 第一,应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。
       第二、Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。
       第三、使用WeakReference代替强引用。比如可以使用WeakReference<Context> mContextRef;
发表于 2017-11-13 09:29:13 回复(0)
1、一次下载过大的文件,如图片  2、其他应用或进程占用过多内存导致,程序所需的内存不够



发表于 2017-08-30 15:37:55 回复(0)
内存泄露的情况:
  • 资源对象没关闭造成的内存泄露,try catch finally中将资源回收放到finally语句可以有效避免OOM。资源性对象比如:
    • ***(register unregister add listener remove listener)
    • cursor 的关闭(try / catch finally 记得 cursor.close)
    • InputStream/OutputStream
  • 内存对象的重复利用
    • LRUCache 与 DiskLruCache( 内存缓存 存储缓存)
    • 避免 onDraw 中创建对象(onDraw 会频繁调用)
    • StringBuilder 代替 +
    • listView 的复用
  • 减少对象的内存复用
    • 使用轻量的数据结构(ArrayMap SparseArray 代替 HashMap)
    • 避免使用 Enum
  • Bitmap
    • inSampleSize (缩放大小)和decode format (解码形式)
    • 使用更小的图片(有一张很大的图片被XML文件直接引用,很有可能在初始化视图的时候就会因为内存不足而发生InflationException,这个问题的根本原因其实是发生了OOM。)
    • 注意 Bitmap 的及时回收。
  • 注意Activity 的泄露。
    • 内部类的引用导致Activity泄露,
    • Activity Context的过多引用,可以使用 Application Context 代替 Acitivity Context
    • 属性动画(ObjectAnimator 没有在 onDestroy 中调用 animator.cancel)
发表于 2017-08-28 11:48:38 回复(0)
1. xml文件完成帧动画的加载,item过多特别容易造成OOM。  解决:自己去处理要加载的图片,decodeFactory加载图片字节流
2. 加载大量的图片,也就是生成了大量的BitMap对象    解决:设置BitMapFactory.options.inSampleSize参数,对图片进行缩放;对于图片使用缓存机制,二级缓存(内存LruCache+本地DiskLruCache)+网络获取
3. view的onDraw方法里面,不要大规模创建对象
4. 有严重的内存泄露:使用MAT或者leakCanary查看相应代码是否有内存泄露。
    内存泄露避免:1. 不要使静态变量长期引用某个非静态变量
                             2. 避免非静态内部类具有静态实例
                             3.使用某些资源时记得关闭,即执行close方法  
发表于 2017-08-24 20:01:58 回复(0)
G^J头像 G^J

一、OOM原因:

1、内存泄露

a) 如果Context对象发生了内存泄露,比如像Activity这样的重量级Context对象引用了大量很占内存的对象,例如View层级以及其他的资源,一旦Context对象发生泄露,那它引用的所有对象都发生泄露,很容易发生OOM

b) 静态Activity,在生命周期结束之前没有被清除引用

c) 静态View,一个view被加入到界面,会持有Context(Activity或者Fragment)的强引用,如果一个静态成员引用了这个view,也即引用了一个Context,在生命周期结束之后若仍然保持引用则导致内存泄露

d) 内部类静态成员引用外部类成员,内部类可以引用外部类成员,是因为持有外部类的引用。同样匿名内部类也会持有定义他们的对象的引用,比如在Activity里定义一个匿名的AsyncTask对象就很有可能发生内存泄露,在Activity销毁之后,AsyncTask还在执行,就会阻止gc,直到执行结束才能回收。

同理,定义一个匿名Runnable对象并提交到Handler,也可能发生Activity泄露,Runnable对象间接地引用了定义它的Activity对象,被提交到Handler的MessageQueue中,如果在Activity销毁之后还没有被处理,则导致泄露

同理还有Thread和TimeTask等,只要是匿名内部类都会持有定义他们的外部类的引用

e) 系统服务,Context对象注册服务之后,服务内部持有Context对象的引用,所以在Context生命周期结束之前没有注销服务的话就会发生内存泄漏

f) Cursor、IO对象没有及时关闭

g) Bitmap使用后没有recycle()

2、占用内存过大

a) 频繁创建对象

b) 图片资源加载过多,例如Bitmap

c) 重复创建View

二、避免OOM:

1、避免内存泄露

a) 对于大部分非必须使用Activity Context的情况(Dialog的Context必须是Activity Context),我们可以考虑使用Application Context

b) 及时关闭Cursor对象、IO对象

c) 注意服务或***的注销

d) 使用静态内部类,其中拥有对外部类的WeakReference

2、减小对象的内存占用

a) 使用更加轻量的数据结构,考虑使用ArrayMap/SparseArray而不是HashMap

b) 避免使用Enum,Enums比静态变量占用两倍以上的内存

c) 减小Bitmap对象的内存占用,重采样、压缩、使用合适的格式解码,使用ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差异

d) 使用对象池来对进行内存对象的重复利用

e) listview应用用convertView和静态ViewHolder

编辑于 2017-08-24 16:08:26 回复(0)
获取日志上传服务器分析
jvm 或者Java代码存在
发表于 2017-08-03 12:25:18 回复(0)
不断创建对象会产生堆溢出, 要控制好对象的创建数量,及时释放对象句柄,
不断调用String.intern(),导致常量池溢出,
通过运行时动态生成大量的class,导致方法区溢出,
JVM在运行方法时,无法申请到足够的内存,会导致虚拟机栈和本地方法栈溢出,
通过unsafe方法,操作直接内存,会导致直接内存溢出。
发表于 2017-07-22 18:34:19 回复(0)