这两天在研究性能中内存方面的一块, 网上也零散看了挺多文章, 写得很细但是感觉不够整体, 所以这篇算是总结一下吧, 当个复习资料
那么这里个人分为两个大部分, 第一部分应用内的内存管理, 主要是 oom 的理解, GC 机制和内存泄露这三个小部分; 另一部分是系统级别的内存管理, 包括内存共享, 进程创建到 LMK 也就是消亡的一个简要了解, 具体到某个细节, 网上挺多的, 就不细说了, 后续看心情再补写!
应用内的内存管理
一) 为什么会发生 OOM
Android 系统为每一个运行的程序都指定了一个最大运行内存, 超过这个值则会触发 OOM 机制, 反应在界面就是闪退 crash 现象, 导致 OOM 发生的原因比如内存泄露或者是代码不考虑后果使用大量的资源, 都有可能导致 OOM 出现的 OOM 的临界值可以通过 adb shell getprop | grep heap 查看到
比如这里, heapgrowthlimit 是默认单个 app 最大内存, heapsize 则是 manifest 文件里设置 android:largeHeap=true, 则会使用这个最大值
二)android 里的 GC 机制
GC 机制沿用了 java 的 GC 机制, 当需要新内存去分配对象的时候而剩余不够的时候, 会触发 GC, 把无用的对象回收掉, 其中一个重要的算法便是分代式算法, 这个算法把虚拟机分为年轻代老年代和持久代, 对象先分配到年轻代, 然后 GC 多次后还存活的将会移动到老年代, 老年代就不会频繁触发 GC 机制, 一般触发频繁的都是年轻代的对象
三) 为什么会内存泄露
第二点我们知道了 GC 机制, 那么如果 GC 过后程序还是没有内存, 那么会发生 OOM, 导致 GC 后还是没有足够内存分配新对象的主要原因就是内存泄露了首先要知道内存泄露也就是 GC 不掉的根源是生命周期长的对象持有生命周期短的对象, 导致无用的对象一直无法回收下面来看看几个典型的分类:
** 静态类相关的泄露:**static 对象的生命周期伴随着整个程序的生命周期, 所以这块要注意不要把一些对象引用添加到 static 对象里面去, 会造成与之关联的对象无法回收
各种资源的释放: 很多了, 包括 cursor 的关闭, IO 流的关闭, bitmap 的回收等等, 进行一些带有缓存的资源一定要关闭或者释放
Handler 的泄露: 调用 handler 的 delay 的时候, 会被认为对象是有用的, 导致无法回收, 还有 handler 开启线程去下载东西没有下载完成的时候, 也会因为线程导致无法回收 activity; 或者使用 handlerThread 的时候, 有延迟的方法, 都会导致无法回收其主要原因在于 handler 是持有 activity 的引用, 你看主线程不是自带一个 Looper 然后给 handler 用嘛, 导致有关联关系
各种注册引用方法: 比如一个常驻的后台线程处理某些时间, 把当前对象注册, 因为一直持有对象引用, 导致这个 activity 一直保留, 所以不用的时候需要反注册
把对象缓存进容器内却忘记 remove 掉: 有时候为了加快页面响应, 结果缓存一些对象到容器内, 结果越加越多, 然后挂掉, 网上有这个例子, 虽然我暂时还没碰到, 一块写了
系统级别的内存管理
一) zygote 的内存共享
我们知道我们的应用进程都是由 zygote fork() 出来的, 包括系统服务和用户程序这块的内存共享主要共享的是通用的资源内存, 比如自带的主题样式, 这样就避免了浪费内存空间读取一样的资源了
二)LMK 机制和 oom_adj 的值
Android 内核有个专用的驱动 low-memory-kill, 当系统级别的内存不够的时候会根据 oom_adj 的值以及内存分配状况去 kill 掉某个进程, oom_adj 可以在 / proc/[pid]/oom_adj 看到, 并且这个值会随着进程的状态改变而改变, 比如系统进程一般是 - 16, 越大越容易被干掉
三) 5 个进程的优先级
前台进程: 当前运行的, 基本不死
可见进程: 界面可以见到, 比如被遮挡
服务进程: 进程带后台服务的, 比如播放器
后台进程: 点击 home 键, 但不退出, 就是后台进程了, 有比较大几率会被杀
空进程: 退出应用程序, 还在后台保留这空进程, 为的是加快启动速率, 最优先杀的对象
四) 共享内存
安卓的内存的管理是分页和内存映射的, 一个 android 程序运行的时候, 会把虚拟内存通过内存映射的方式给到运行的进程, 当真正要执行这块内容的时候, 会通过分页的当时去分配实际内存, 那么虚拟内存包括什么东西呢?
在 linux 环境下, 通过命令
pmap -x [pid]
1
可以查询虚拟内存空间实例
可以看到虚拟内存的空间主要是包括这些的, 代码段, 堆栈, 匿名共享内存, 动态链接库等等
这里又出现了一个名词, 匿名共享内存, 实际上这是系统开辟一个内存空间, 然后映射到进程的虚拟空间, 可以实现多进程共享, 比如 android 的显示过程, 处理好的 surface 交给 surfaceFlinger 服务, 服务则是通过匿名共享内存的方式给缓冲区再进一步绘制我们看到的图像
好了, 总结一下, android 涉及的共享内存, 一个是 zygote 生出的子代, 共享 android 的一些资源, 一些类库, 一些数据第二个是匿名共享内存, 包括 surface, 图形驱动音频驱动等等
来源: http://www.bubuko.com/infodetail-2516779.html