背景
笔者最近承接项目的内存优化工作,在预研的过程中发现一篇关于内存优化的文章 《优化安卓应用内存的神秘方法以及背后的原,理,一般人我不告诉他》
里面介绍了一个方法
WindowManagerGlobal.getInstance().startTrimMemory(TRIM_MEMORY_COMPLETE);
但是应用层无法直接访问 WindowManagerGlobal,因此笔者采取反射来验证这个方案的可行性。
方案实现
首先, WindowManagerGlobal 在 android 5.0 开始已经没有 startTrimMemory()的声明,改为了 trimMemory()
private fun startTrimMemory() {
try {
val windowManagerGlobalClass = Class.forName("android.view.WindowManagerGlobal")
val getInstanceMethod = windowManagerGlobalClass.getDeclaredMethod("getInstance")
val windowManagerGlobalInstance = getInstanceMethod.invoke(null)
val startTrimMemoryMethod = windowManagerGlobalClass.getDeclaredMethod(
"trimMemory",
Int::class.javaPrimitiveType
)
// TRIM_MEMORY_COMPLETE 对应的值为 80
val trimMemoryCompleteValue = 80
startTrimMemoryMethod.invoke(windowManagerGlobalInstance, trimMemoryCompleteValue)
} catch (e: Throwable) {
}
}
项目中打开视频播放页面,播放视频,待内存稳定后,退出播放页面,观察内存变化:
播放页面,播放视频中
退出播放页面后
对比看出, Graphics 内存下降最为明显, Java 部分内存次之,其他部分变化不大。
如同原文作者所说 “应用开发者调用 startTrimMemory 会帮助 app 或者系统更多的释放内存,减少内存压力,但是调用的位置和时机要慎重,因为清除了缓存,在下一次绘制(vsync的下一个信号到来)的时候绘制效率不会很高。”
目前方案验证有效,但是在实际项目中还需要探索验证调用的场景和时机,后续笔者上线后更新效果。
来更新效果了:
很可惜,线上跑的时候会新增少量 native 崩溃
在 POSIX 兼容的平台上,SIGSEGV 是当一个进程执行了一个无效的内存引用,或发生段错误时发送给它的信号。SIGSEGV 的符号常量在头文件 signal.h 中定义。因为在不同平台上,信号数字可能变化,因此符号信号名被使用。通常,它是信号11。
对于不正确的内存处理,如当程序企图访问 CPU 无法定址的内存区块时,计算机程序可能抛出 SIGSEGV。
手动清除 GPU 内存可能还是有风险,毕竟这个方法是系统调用的,系统本身有管理 GPU 内存机制。而作者当时提的这个方案《优化安卓应用内存的神秘方法以及背后的原理,一般人我不告诉他》,我猜想当时设备没有那么多样性,当时那个环境方案应该是可行的,如今各种不同的厂商和设备,系统底层都有自己的定制化修改,真的不可同日而语。当然,崩溃的引发可能也和我业务的调用场景有关,笔者后面也会继续做实验看看有没可应用的场景。
总结
尽管降低内存效果很不错,无奈暂时只能弃坑。 后续有新发现再更新~