企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] # 内存问题 ## 内存泄漏 内存泄露是指没有用的对象由于某种原因程序未释放或无法释放,造成系统内存的浪费。Android常见的场景有 * 非静态内部类隐式持有外部类的引用导致的泄漏,包括: 2. 非静态内部类的静态实例 3. 多线程相关的匿名内部类/非静态内部类 解决办法:变静态 4. Handler 解决办法1.变静态 2.在onDestory移除MessageQueue mHander.removeCallbacksAndMessages(null) * 静态View * WebView,只要使用过一次的WebView,内存就不会被释放。解决办法:为webView单独开一个进程 * 资源未释放,如File、Cursor,往往使用可缓存。解决办法:在finally中进行关闭 * bitmap * 无限制的使用缓存 * 系统组件导致的泄漏,如[InputMethodManager 导致的泄漏](https://www.jianshu.com/p/62e498075e56),[Drawable泄露](https://www.jianshu.com/p/914888735ce5)。 * 线程过度使用,线程初始化都需要 mmap 一定的 stack size, ## 内存抖动 内存抖动是由于短时间内有大量对象进出新生区导致的,它伴随着频繁的GC。  gc会大量占用ui线程和cpu资源,会导致app整体卡顿 ## 内存溢出 OOM ### 堆空间不足发生OOM 1. 当你的app启动后,系统会分配给app一个堆空间,起始不会很大比如是32M(根据你的app启动时的内存申请为准) 2. 随着程序的运行对象的创建越来越多,系统不断加内存分配:32M -> 64M -> ... 3. 而GC回收则会定时扫描内存,发现不被引用的对象即可回收。正常来说你的app堆内存会有升有降。 4. app运行一段时间堆内存超过系统规定的最大值 heapSize,杯子满了就会发现内存溢OOM,app崩溃。 ### heapSize大小 我们用下面的代码获取heapsize: ~~~ ActivityManager manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); int heapSize = manager.getMemoryClass(); int maxHeapSize = manager.getLargeMemoryClass(); // manafest.xml android:largeHeap="true" ~~~ heapSize是设备分配给app的最大堆内存 maxHeapSize 是当配置了android:largeHeap="true" 才有的最大堆内存,一般是heapSize的2-3倍 以HTC ONE为例,两个值分别是: 192M和512M。这里我只关注192M, ### 线程无法申请OOM(堆内存充裕下发生OOM) ~~~ java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Out of memory ~~~ 每个线程初始化都需要 mmap 一定的 stack size,在默认的情况下一般初始化一个线程需要 mmap 1M 左右的内存空间,在 32位的系统中有 4g 的 vmsize,实际能使用的有 3g+,按这种估算,一个进程最大能创建的线程数可达 3000+,当然这是理想的情况,在 linux 中对每个进程可创建的线程数也有一定的限制(/proc/pid/limits)而实际测试中,我们也发现不同厂商对这个限制也有所不同,而且当超过系统进程线程数限制时,同样会抛出这个类型的 OOM。 **可见对线程数量的限制,可以一定程度避免 OOM 的发生**。所以我们也开始对微信的线程数进行了监控统计。 ### OOM是否可以try catch 只有在一种情况下,这样做是可行的: 在try语句中声明了很大的对象,导致OOM,并且可以确认OOM是由try语句中的对象声明导致的,那么在catch语句中,可以释放掉这些对象,解决OOM的问题,继续执行剩余语句。 但是这通常不是合适的做法。 Java中管理内存除了显式地catch OOM之外还有更多有效的方法:比如SoftReference, WeakReference, 硬盘缓存等。 在JVM用光内存之前,会多次触发GC,这些GC会降低程序运行的效率。 如果**OOM的原因不是try语句中的对象(比如内存泄漏)**,那么在catch语句中会继续抛出OOM # 内存优化 ## 常规手段 内存优化的一些细节问题可以在开发时避免,下面介绍一些常规的内存优化手段 1)、使用`LargeHeap`属性增加最大可用内存 2)、在系统触发资源紧张回调时,主动删除缓存 3)、使用优化过后的集合:如`SparseArray`类等 4)、谨慎使用 `SharedPreference`,`SP`会在应用初始化时将所有内容加载到内存中,所以不应该存放比较大的内容 5)、谨慎使用外部库,引入时需要明确不会对应用性能造成大的影响 6)、业务架构设计要合理,抽象可以优化代码的灵活性和可维护性,但是抽象也会带来其他成本,应权衡使用 ## 图片优化 见【图片内存优化】 # 线上内存监控指标 ## 内存泄漏 ## 内存触底率 ## 大图监控 ## native内存监控 # 参考资料 [Android进阶性能调优;不可思议的OOM](https://www.jianshu.com/p/31f207782915) [微信 Android 终端内存优化实践](https://mp.weixin.qq.com/s/KtGfi5th-4YHOZsEmTOsjg) [性能优化(三)看完这篇文章,至少解决 APP 中 90 % 的内存异常问题](https://juejin.im/post/5cd82a3ee51d456e781f20ce) [【从入门到实用】android内存优化深入解析](https://juejin.cn/post/6975876569990447134)