OOM问题总结

本文介绍了Android应用程序中常见的内存泄露问题及其解决方案,包括避免资源泄漏、合理管理Bitmap资源、使用软引用处理图片加载等方法,并提供了详细的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

OutOfMemoryError(OOM)就是常说的内存泄露问题。为了能够使Android应用程序能够高效快速地运行,

所以Android的每个应用程序都会用一个专有的Davilk虚拟机(Android L 上谷歌使用了传闻已久的ART

来代替Dalvik)实例对象来运行,这个Davilk对象是由Zygote服务进程孵化出来的,这样的机制使每个

应用进程都只能在属于自己的进程空间中运行。Android为不同类型的进程分配了不同的内存使用上限,

也就是设置了一个阈值,当这个上限被超过时,就视为OOM,通过一定的选择策略,某些进程就会被系

统kill掉以释放内存。如果你正在开发一个应用,想知道设备的heap大小的限制是多少,比方说根据这个

值来估算自己应用的缓存大小应该限制在什么样一个水平,你可以使用ActivityManager.getMemoryClass ()

来获得一个单位为MB的整数值。

在编程中有些现象很容易造成造成内存泄露,我们应该尽量避免:
一.引用没释放造成的内存泄露
二.资源对象没关闭造成的内存泄露(比如没有关闭访问文件的输入输出流)
三.Bitmap没调用recycle(Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后才它设置为null.)
四.构造Adapter时,没有使用缓存的 convertView
五.一些不良代码成内存压力(一些代码虽然不会直接造成内存泄露,但是它一直占用内存就会影响其他进程访问内存,间接造成OOM)

六.大量读取图片,比如listview或者相册,读取网络图片时,使用软引用(SoftReference),让系统能够自动的利用内存空间

解决方法:

一、处理图片时可以使用弱引用,jvm会更快的回收资源。创建Bitmap时,可以使用BitmapFactory.decodeStream(is)代替createBitmap这个方法。同时,用完的bm要尽快回收。

二、在做项目中遇到类似的问题,原因在于使用的图片在不用后未能及时回收资源。
if(!bitmap.isRecyle()){
bitmap.recycle();
System.gc();
bitmap=null;
}

三、对于一些内存非常吃紧的比如图片浏览器等应用,在平板上所需的内存更大了。因此在AndroidManifest.xml里增加了largeHeap的选项

1
2
3
4
<application
       android:largeHeap="true"
       ...
</application>
这允许你的应用使用更多的heap,可以用ActivityManager.getLargeMemoryClass ()返回一个更大的可用heap size。但是这里要警告的是,千万不要因为你的应用报OOM了而使用这个选项,因为更大的heap size意味着更多的GC时间,意味着应用的性能越来越差,而且用户也会发现其他应用很有可能会内存不足。只有你需要使用很多的内存而且非常了解每一部分内存的用途,这些所需的内存都是不可或缺的,这个时候你才应该使用这个选项。

常用分析方法:

解决这类问题的关键还是要找到复现的方法,通过复现方法结合代码逻辑进行分析。我把目前为止在工作中遇到过的此类问题分为一下几类。

问题一:代码逻辑中已经实现了对资源引用的回收处理,但还是出现OOM问题

分析:工程师在设计功能的时候都是从典型用户的使用习惯触发的,由于测试人员非常规的随机的操作,导致应用始终无法走到相应的回收逻辑,旧的资源无法回收。同时,不断重复相同的操作,新的资源又被不断重复申请,最终出现OOM,应用FC。

解决办法:对于这类问题,通常的解决办法是通过修改代码逻辑规避用户进行如此操作。这样做是因为代码本身已经实现了资源回收逻辑,如果在这种非典型的用户操作过程中强行调用回收处理,很有可能会影响到后续逻辑的执行,也可能导致应用在正常用户行为下表现异常。遇到实际问题的时候,还是要评估一下做规避处理和强行调用回收处理这两种方法的改动量和风险。因为这是一个非典型的用户行为,评估后发现强行调用回收处理有上述风险,所以最后采用的规避处理,使得用户无法进行测试时的操作来解决这个问题。

问题二:代码逻辑中缺失资源回收处理导致OOM

分析:这类问题大多是因为跟图片相关的资源未做回收处理。最近就遇到一个这类问题,由于回收不完全使得相关的实例无法回收,而每次进行相同操作的时候都要重新实例化一个对象,而这个对象又绑定了一个包含了一张非常大图片的layout,layout也存在多个实例,导致内存无法释放出现OOM。

解决办法:在OnDestroy的时候做相应的回收,使得相关实例能够正常回收。

问题三:图片资源没有及时回收

分析:这类问题多是为了做代码优化以适配系统性能比较差的设备。

解决方法:当系统剩余内存比较低的时候onTrimMemory函数就会被调用,可以重新实现onTrimMemory函数,对不是正在使用的资源进行回收。重新实现OnLowMemory函数应该也是同样原理,没试过没啥发言权,大家可以自己尝试一下。

以上纯属个人观点,有些问题由于时间有点久了记得不是很清楚了,多少有些出入,但大致方向应该是没问题的。另外,跟大家分享一个小技巧。分析OOM这类问题大多数时候还是要分析hprof文件的,但是遇到屏幕分辨率比较大或是测试case比较复杂的情况,hprof文件会异常的大,获取也异常困难。使用工具抓取往往会导致应用重启或是DDMS闪退,可以尝试一下命令通过adb抓取。

                                              adb shell am dumpheap <pid> /data/data/<app package name>/files/dumpheap.hprof





下面的链接是关于分析OOM问题的介绍,写的非常详细,还有相关配图,便于理解。

http://www.360doc.com/content/14/0526/11/9462341_381066152.shtml

http://blog.csdn.net/chengyingzhilian/article/details/8662849


如何下载及配置MAT

http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html

小技巧:


相关连接:

http://www.dewen.io/q/1401

http://www.360doc.com/content/14/0526/11/9462341_381066152.shtml

<think>我们正在处理关于Java内存溢出(OOM问题的排查和解决方案。根据引用内容,我们可以总结出以下关键点:1.使用JProfile等工具进行内存分析(引用[1])2.不同类型的OOM错误及其原因和解决方案(引用[2])3.内存溢出的重要性(引用[3])4.内存分析中的关键概念:ShallowSize和RetainedSize(引用[4])因此,我们可以组织一个关于OOM问题排查和解决方案的详细回答,包括:-常见OOM错误类型及其原因-使用工具(如JProfile)进行排查的步骤-解决方案和预防措施同时,按照用户要求,我们需要在回答末尾生成相关问题。注意:回答中引用的段落末尾要添加引用标识,例如[^1]</think>### Java OOM 问题排查与解决方案 #### 一、常见 OOM 类型及解决方案 1. **`java.lang.OutOfMemoryError: Java heap space`** - **原因**:堆内存不足,对象数量超过堆容量 - **解决方案**: - 使用 `-Xmx` 增大堆大小(如 `-Xmx4g`) - 检查内存泄漏(重点分析大对象)[^1] - 优化数据结构(避免冗余对象) 2. **`java.lang.OutOfMemoryError: GC overhead limit exceeded`** - **原因**:GC 耗时超过 98%,回收效率过低[^2] - **解决方案**: - 分析堆转储文件(`jmap -dump`) - 减少短生命周期对象创建 - 调整 GC 策略(如 G1 GC) 3. **`java.lang.OutOfMemoryError: Metaspace`** - **原因**:元空间(类元数据)耗尽 - **解决方案**: - 增加 `-XX:MaxMetaspaceSize` - 检查类加载器泄漏(尤其动态生成类场景) 4. **`java.lang.OutOfMemoryError: Unable to create new native thread`** - **原因**:线程数超过系统限制 - **解决方案**: - 减少线程数量(使用线程池) - 调整 `ulimit -u` 系统参数 #### 二、排查工具使用流程 1. **获取堆转储** ```bash jmap -dump:format=b,file=heapdump.hprof <pid> ``` 2. **使用 JProfile 分析** - **步骤**: - 观测内存实时变化(Memory 视图) - 定位 **Retained Size** 大的对象(实际可释放内存)[^4] - 检查 **Leak Suspects**(泄漏嫌疑对象) - **关键操作**: - 对比多次快照中的对象增长 - 分析对象引用链(Dominator Tree) 3. **MAT 内存分析工具** - 查看 **Shallow Heap**(对象自身内存)[^4] - 检测重复对象(Duplicate Classes) #### 三、通用优化策略 1. **代码层面** - 及时释放资源(`close()` 流/连接) - 避免静态集合长期持有对象 - 使用软引用/弱引用缓存 2. **JVM 参数调优** ```bash -XX:+HeapDumpOnOutOfMemoryError # 自动生成Dump -XX:MaxMetaspaceSize=256m # 控制元空间 -XX:+UseG1GC # 启用G1垃圾回收器 ``` 3. **监控与预防** - 部署 APM 工具(如 Arthas)实时监控 - 压力测试时进行堆分析 - 设置合理的熔断机制 > **关键提示**:90% 的 OOM 由内存泄漏引起,需重点关注未释放的对象引用链[^3]。 ####
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值