大厂的OOM优化和监控方案(二)

简介: 大厂的OOM优化和监控方案(二)
  • 四、打开太多文件
  • 4.1 错误信息
  • 4.2 系统限制
  • 4.2 文件描述符优化
  • 4.3 文件描述符监控
  • 4.4 IO监控

四、打开太多文件

4.1 错误信息

E/art: ashmem_create_region failed for 'indirect ref table': Too many open files
Java.lang.OutOfMemoryError: Could not allocate JNI Env

这个问题跟系统、厂商关系比较大

4.2 系统限制

Android是基于Linux内核,/proc/pid/limits 描述着linux系统对每个进程的一些资源限制,

如下图是一台Android 6.0的设备,Max open files的限制是1024

微信图片_20220906140735.jpg

如果没有root权限,可以通过ulimit -n命令查看Max open files,结果是一样的

ulimit -n

微信图片_20220906140754.jpg

Linux 系统一切皆文件,进程每打开一个文件就会产生一个文件描述符fd(记录在/proc/pid/fd下面)

cd /proc/10654/fd

ls

微信图片_20220906140813.jpg

这些fd文件都是链接文件,通过 ls -l可以查看其对应的真实文件路径

微信图片_20220906140830.jpg

当fd的数目达到Max open files规定的数目,就会触发Too many open files的奔溃,这种奔溃在低端机上比较容易复现。

知道了文件描述符这玩意后,看看怎么优化~

4.2 文件描述符优化

对于打开文件数太多的问题,盲目优化其实无从下手,总体的方案是监控为主。

通过如下代码可以查看当前进程的fd信息

private fun dumpFd() {
        val fdNames = runCatching { File("/proc/self/fd").listFiles() }
            .getOrElse {
                return@getOrElse emptyArray()
            }
            ?.map { file ->
                runCatching { Os.readlink(file.path) }.getOrElse { "failed to read link ${file.path}" }
            }
            ?: emptyList()
        Log.d("TAG", "dumpFd: size=${fdNames.size},fdNames=$fdNames")
    }

4.3 文件描述符监控

监控策略:当fd数大于1000个,或者fd连续递增超过50个,就触发fd收集,将fd对应的文件路径上报到后台。

这里模拟一个bug,打开一个文件多次不关闭,通过dumpFd,可以看到很多重复的文件名,进而大致定位到问题。

微信图片_20220906140912.jpg

当怀疑某个文件有问题之后,我们还需要知道这个文件在哪创建,是谁创建的,这个就涉及到IO监控~

4.4 IO监控

4.4.1 监控内容

监控完整的IO操作,包括open、read、write、close

open :获取文件名、fd、文件大小、堆栈、线程

read/write :获取文件类型、读写次数、总大小,使用buffer大小、读写总耗时

close :打开文件总耗时、最大连续读写时间

4.4.2 Java监控方案:

以Android 6.0 源码为例,FileInputStream 的调用链如下

java : FileInputStream -> IoBridge.open -> Libcore.os.open ->  
 BlockGuardOs.open -> Posix.open

Libcore.java是一个不错的hook点

package libcore.io;
public final class Libcore {
    private Libcore() { }
    public static Os os = new BlockGuardOs(new Posix());
}

我们可以通过反射获取到这个Os变量,它是一个接口类型,里面定义了open、read、write、close方法,具体实现在BlockGuardOs里面。

// 反射获得静态变量
Class<?> clibcore = Class.forName("libcore.io.Libcore");
Field fos = clibcore.getDeclaredField("os");

通过动态代理的方式,在它所有IO方法前后加入插桩代码来统计IO信息

// 动态代理对象
Proxy.newProxyInstance(cPosix.getClassLoader(), getAllInterfaces(cPosix), this);
beforeInvoke(method, args, throwable);
result = method.invoke(mPosixOs, args);
afterInvoke(method, args, result);

此方案缺点如下:

  • 性能差,IO调用频繁,使用动态代理和Java的字符串操作,导致性能较差,无法达到线上使用标准
  • 无法监控Native代码,这个也是比较重要的
  • 兼容性差:需要根据Android 版本做适配,特别是Android P的非公开API限制

4.4.3 Native监控方案

Native Hook方案的核心从 libc.so 中的这几个函数中选定 Hook 的目标函数

int open(const char *pathname, int flags, mode_t mode);
ssize_t read(int fd, void *buf, size_t size);
ssize_t write(int fd, const void *buf, size_t size); write_cuk
int close(int fd);

我们需要选择一些有调用上面几个方法的 library,例如选择libjavacore.so、libopenjdkjvm.so、libopenjdkjvm.so,可以覆盖到所有的 Java 层的 I/O 调用。

不同版本的 Android 系统实现有所不同,在 Android 7.0 之后,我们还需要替换下面这三个方法。

open64
__read_chk
__write_chk

native hook 框架目前使用比较广泛的是爱奇艺的xhook ,以及它的改进版,字节跳动的bhook。

具体的native IO监控代码,可以参考 Matrix-IOCanary,内部使用的是xhook框架。

关于IO涉及到的知识非常多,后面有时间可以单独整理一篇文章。

接下来看看最后一种OOM类型~

相关文章
|
Web App开发 Android开发 iOS开发
iOS 调试:通过 Safari/Chrome 调试 WebView
iOS 调试:通过 Safari/Chrome 调试 WebView
11298 123
iOS 调试:通过 Safari/Chrome 调试 WebView
|
JSON 小程序 前端开发
微信小程序(二十四)微信小程序富文本编辑器editor
{ "component": true, "usingComponents": {} }
660 0
|
人工智能 自然语言处理 安全
AI战略丨新一代 AI 应用: 穿透场景,释放价值
在深入理解技术特性、准确把握应用场景、科学评估实施条件的基础上,企业才能制定出符合自身实际的战略。
|
10月前
|
数据可视化 数据挖掘 大数据
基于python大数据的水文数据分析可视化系统
本研究针对水文数据分析中的整合难、分析单一和可视化不足等问题,提出构建基于Python的水文数据分析可视化系统。通过整合多源数据,结合大数据、云计算与人工智能技术,实现水文数据的高效处理、深度挖掘与直观展示,为水资源管理、防洪减灾和生态保护提供科学决策支持,具有重要的应用价值和社会意义。
|
SQL 缓存 关系型数据库
SQL为什么不建议执行多表关联查询
本文探讨了SQL中不建议执行多表关联查询的原因,特别是MySQL与PG在多表关联上的区别。MySQL仅支持嵌套循环连接,而不支持排序-合并连接和散列连接,因此在多表(超过3张)关联查询时效率较低。文章还分析了多表关联查询与多次单表查询的效率对比,指出将关联操作放在Service层处理的优势,包括减少数据库计算资源消耗、提高缓存效率、降低锁竞争以及更易于分布式扩展等。最后,通过实例展示了如何分解关联查询以优化性能。
563 0
|
安全 API 开发工具
Android14 适配之——targetSdkVersion 升级到 34 需要注意些什么?(下)
Android14 适配之——targetSdkVersion 升级到 34 需要注意些什么?(下)
2338 0
|
关系型数据库 MySQL
mysql最大连接数怎么设置
mysql最大连接数怎么设置
2352 0
mysql最大连接数怎么设置
|
移动开发 安全 网络安全
Https中间人攻击
Https中间人攻击
928 0
|
监控 JavaScript Java
大厂的OOM优化和监控方案(一)
大厂的OOM优化和监控方案(一)
大厂的OOM优化和监控方案(一)