都写在一篇里面有点太长了...且很难满足日更的要求,所以多拆几篇,每篇写个5个参数,岂不是更美滋滋
minfree_levels
Very, very important 的参数,简直是工作旅行居家必备!
我们使用日常使用手机的过程中,经常发现后台进程被kill了,是因为除了oom外,安卓还有一套主动kill进程来释放内存的机制。
- 在Android P及以前版本中,这套机制叫lowmemorykiller,运行在内核态中。
这是在旧版本中查看参数的方式,基本上被淘汰了,我们就不研究了。
sys/module/lowmemorykiller/parameters/minfree
sys/module/lowmemorykiller/parameters/adj
- 在Android Q及之后,为了使用方便,将这套机制移动到用户态,叫lmkd。
通过*adb shell "getprop sys.lmk.minfree_levels"获取,需要root权限哈。
[sys.lmk.minfree_levels]: [18432:0,23040:100,27648:200,32256:250,110592:900,161280:950]
类似map的数组,0,100,200,250,900,950 代表6个不同的进程优先级,
数值越高越早被杀,前面的则代表当前查杀水线,单位是page,
例如可用内存低于161280页,就可以查杀优先级950后的进程
算了,lmkd好复杂,我单开一篇写吧┭┮﹏┭┮这里就只讲下如何调整
platform/frameworks/base/ services/core/java/com/android/server/am/ProcessList.java
让我们see see代码
// These are the low-end OOM level limits. This is appropriate for an
// HVGA or smaller phone with less than 512MB. Values are in KB.
private final int[] mOomMinFreeLow = new int[] {
12288, 18432, 24576,
36864, 43008, 49152
};
// These are the high-end OOM level limits. This is appropriate for a
// 1280x800 or larger screen with around 1GB RAM. Values are in KB.
private final int[] mOomMinFreeHigh = new int[] {
73728, 92160, 110592,
129024, 147456, 184320
};
// The actual OOM killer memory levels we are using.
private final int[] mOomMinFree = new int[mOomAdj.length];
for (int i = 0; i < mOomAdj.length; i++) {
int low = mOomMinFreeLow[i];
int high = mOomMinFreeHigh[i];
if (is64bit) {
// Increase the high min-free levels for cached processes for 64-bit
if (i == 4) high = (high * 3) / 2;
else if (i == 5) high = (high * 7) / 4;
}
mOomMinFree[i] = (int)(low + ((high - low) * scale));
}
if (minfree_abs >= 0) {
for (int i = 0; i < mOomAdj.length; i++) {
mOomMinFree[i] = (int)((float)minfree_abs * mOomMinFree[i]
/ mOomMinFree[mOomAdj.length - 1]);
}
}
if (minfree_adj != 0) {
for (int i = 0; i < mOomAdj.length; i++) {
mOomMinFree[i] += (int)((float) minfree_adj * mOomMinFree[i]
/ mOomMinFree[mOomAdj.length - 1]);
if (mOomMinFree[i] < 0) {
mOomMinFree[i] = 0;
}
}
}
if (write) {
ByteBuffer buf = ByteBuffer.allocate(4 * (2 * mOomAdj.length + 1));
buf.putInt(LMK_TARGET);
for (int i = 0; i < mOomAdj.length; i++) {
buf.putInt((mOomMinFree[i] * 1024)/PAGE_SIZE);
buf.putInt(mOomAdj[i]);
}
writeLmkd(buf, null); //通过handler传递数据
一通计算xx,算出数组后传到底层。在日常项目中,我们经常把最后2个等级调大1.5倍左右,这个需要反复调整,高低端机的效果会不同。
page-cluster
page-cluster是用来控制从swap空间换入数据的时候,一次连续读取的页数,这相当于对交换空间的预读。这里的连续是指在swap空间上的连续,而不是在内存地址上的连续。
void __init swap_setup(void)
{
unsigned long megs = totalram_pages >> (20 - PAGE_SHIFT);
/* Use a smaller cluster for small-memory machines */
if (megs < 16)
page_cluster = 2;
else
page_cluster = 3;
/*
* Right now other parts of the system means that we
* _really_ don't want to cluster much more
*/
}
用我小学数学心算了一下,总内存小于16M,就设为2,否则设为3,没算错把?
不过我们领导让我全都改成0了。
compact_memory
内核提供了接口给用户触发规整动作,接口如下:/proc/sys/vm/compact_memory只要往这个节点写值即可触发对系统所有node管理的内存做内存规整。
int sysctl_compaction_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *length, loff_t *ppos)
{
if (write)
compact_nodes();
return 0;
}
-> compact_nodes(void)
然后->compact_node(int nid)
再对每一个zone:
for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) {
...
compact_zone(&cc, NULL);
...
}
compact_zone() 卧槽这个好难,呜呜呜看不懂
swappiness
看一下官方介绍:
swappiness用于控制kswapd内核线程把页面写入交换分区的活跃程度,设置的区间为0-100。
- 该值越小,说明写入交换分区的活跃度越低,有助于提高系统的I/O性能。
- 该值越大,说明更多进程的匿名页面被写入交换分区,有利于系统腾出内存空间,但是发生磁盘交换会导致大量的IO,影响系统的用户体验和系统性能。不过在Android设备上,采用了ZRAM机制,将部分内存作为swap空间避免IO操作。
0表示不写入匿名页面到磁盘,直到系统的空闲页面加上文件映射页面的总数小于内存管理区的高水位才启动匿名页面回收并写入交换分区。
swappiness的默认值为60。
优化思路:
- ZS_MAX_ZSPAGE_ORDER调大,ISOLATED_ISOLATED_BITS调大
- 扫描的时候,对于kswapd线程,偏好量设置为80%,非kswapd线程,可以设置为30%
- 对于高端机(内存较大)而言,可以动态调整kswapd的swappiness,如果文件页面充足的情况下,每次get_scan_count的时候,可以临时调低swappiness的值,来降低kswapd的负载
zram主要参数
紧跟上文一起介绍
zram是将部分内存拿出作为交换空间的手段,既避免来IO的耗时操作,又增大来可用内存。那么,拿出多少空间作为zram最优呢,光交换不压缩也没有起到节省空间的作用,那么使用何种压缩算法更能均衡性能呢?
- disksize zram空间大小设定,位于/sys/block/zram0/disksize,mtk平台默认的设置是总内存的55%,还是比较合理的。具体对于每个内存size的设定,就需要不同场景下的性能模型测试结果来做出选择。
- comp_algorithm 压缩算法,随着lz0的淘汰,现在主流的2种算法是,lz4(压缩比接近1:3),和zstd(压缩比接近1:5) 这个可以通过dumpsys meminfo在底部的zram使用中估算。
压缩率高的更占cpu算力,所以zstd适合CPU性能强但内存小的设备,lz4则是默认配置。
设置disksize必须要在设置压缩算法comp_algothrim后面
如何修改呢?
- 高通平台可以在
device/qcom/commom /rootdir/etc/init.qcom.post_boost.sh
添加个函数直接修改,zstd算法还得打开CONFIG_CRYPTO_ZSTD = y的宏
- MTK平台的话就得自己写个sh脚本了
在init.mtxxxx.rc中
service swap_enable _init /vender/bin/sh /vender/bin/swap.sh
user root
disable
oneshot