OOM 机制

When a system runs out of memory, the OOM killer makes a decision about what process to kill base on its own policy. First, it chooses the process which currently owns the most memory to kill. By this policy, it is expected that the process which owns the most memory is the malfunction one. But in my case, even after getting all the remaining available memory of system, the malfunction process is still not a process who held biggest amount of memory, then it happended that the OOM killer killed the process which own most memory, not the malfunction one.

So, now I know that when system log show "Out of memory: kill process <process id>", it doesn't mean that this <process-id> causes the system runs out of memory.

### 什么是OOM? 在Android开发中,OOM代表“Out Of Memory”,即内存不足异常。当应用尝试分配更多内存而系统无法提供足够的可用内存时,就会抛出`OutOfMemoryError`[^1]。 --- ### 为什么会发生OOM? 尽管Android拥有垃圾回收器(Garbage Collector, GC),用于自动释放不再使用的对象所占的内存,但如果程序设计不当或者某些特定情况下,仍然会发生内存溢出。主要原因包括但不限于以下几点: - **内存泄漏**:即使对象已经不需要了,但由于被其他长期存在的对象持有引用,导致其无法被GC回收。 - **加载过大的Bitmap或其他资源**:例如一次性加载过多的大尺寸图片到内存中。 - **缓存过大**:不合理的LruCache或DiskCache设置可能导致大量数据驻留在内存中。 - **频繁创建大对象**:短时间内连续创建多个大型对象可能耗尽堆空间[^2]。 --- ### APP的内存限制是多少? 每个Android应用程序都有一定的内存配额,这个数值取决于设备的具体配置和操作系统版本。通常来说,在大多数现代手机上,单个进程的最大允许内存范围大约为: - 中低端设备:约32MB至64MB; - 高端设备:可达192MB甚至更高。 开发者可以通过调用 `ActivityManager.getMemoryClass()` 方法来查询当前设备给予该应用的确切最大内存值 (单位为 MB)[^4]: ```java ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); int maxMemoryInMb = activityManager.getMemoryClass(); System.out.println("Max memory allowed: " + maxMemoryInMb + " MB"); ``` --- ### 为什么Android系统要设定App的内存限制? 为了保障整个操作系统的流畅运行并合理分配有限硬件资源给各个正在执行的任务,因此有必要对每一个单独的应用施加严格的内存约束条件。这样做的好处在于防止某个恶意软件或者其他失控的应用占用全部RAM从而影响用户体验乃至造成系统崩溃[^3]。 --- ### 容易发生OOM的场景及解决方案 #### 场景一:Bitmap处理不当 问题描述:直接通过` BitmapFactory.decodeResource() ` 或者类似的API读取原始图像文件可能会因为分辨率过高而导致超出可承受限度。 解决办法: - 使用采样率缩小图片尺寸后再加载入内存。 - 利用第三方库如Glide/Fresco/Picasso等高效管理图片显示过程中的生命周期绑定关系。 示例代码如下所示: ```java public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); } ``` #### 场景二:静态变量持有Context实例 问题描述:将Activity作为全局静态成员保存下来会造成严重的循环依赖现象,使得原本应该销毁的对象一直存活于后台直至触发错误提示。 解决策略:避免让任何非短期作用域内的实体指向具体UI组件;改用Application Context代替Activity Instance传递参数。 #### 场景三:WebView未正确关闭 问题描述:嵌套Web页面浏览功能模块如果没有显式停止JavaScript引擎工作线程的话,则极有可能遗留下来的空白标签页继续消耗CPU周期与网络流量。 修复措施:每当退出含有此类控件界面之前务必记得清理内部状态信息并通过destroy函数彻底移除关联痕迹。 --- ### 如何有效预防OOM的发生? 1. 对象池技术——复用已有的临时结构体而非重复new出来新的副本; 2. 调整虚拟机启动参数增加初始heap size以及max heap limit; 3. 借助MAT工具深入剖析dump出来的hprof快照找出潜在风险点所在位置; 4. 实践良好的编程习惯比如及时close InputStream OutputStream Reader Writer之类的流型接口; 5. 关注第三方SDK文档说明确保按照推荐方式集成插件以免引入不必要的负担。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值