Android性能优化之游戏 OutOfMemoryError: pthread_create探究真相

近期,着手分析游戏的OOM问题,该问题在bugly上的量级,恐怖吓人的百万级,处于java 异常的top 1, 如下所示:
在这里插入图片描述
发生的设备,基本上都是32位的cpu架构
在这里插入图片描述

分析过程

先来看下报错的堆栈,基本上都是发生在创建线程的环节:
在这里插入图片描述
单纯从java 报错的调用栈来看,往往会简单的认为是app 线程过多导致OOM。然而,事实真的是如此嘛?

先通过adb shell 来,查询下游戏的线程数
在这里插入图片描述
经历游戏的主流程后,发现线程数并没有增加特别多,普遍处于200多上下,没有到达厂商限制最大线程数(华为 设备上限制500+的线程数)。

从而推断出,并不是线程数量过多导致OOM的问题。

接着继续探究,OOM 是内存不足时,再次申请开辟内存失败,从而抛出的异常。

去查看下会不会是系统内存不足,导致的元凶?
在这里插入图片描述
从bugly上统计的数据来看,游戏发生OOM时,系统可用内存还是很充足的,因此也排除了这个原因。

接着继续,分析看下是不是Dalivk Heap内存不足?

java heap OOM异常,会带着,Failed to allocate a 294920 byte allocation with 147040 free bytes and 143KB until OOM,与报错堆栈上的pthread_create (1040KB stack) failed: Try again完全对不上,因此也不是dalvik 堆内存不足导致的。

排除了三个可能性后,结合32位设备,推断唯一剩下的便是app 的虚拟内存不足。

更多有关于内存情况,请阅读Android 内存分析(java/native heap内存、虚拟内存、处理器内存 )Android adb shell 查看App内存(java堆内存/vss虚拟内存/详细的内存状况/内存快照hprof)和系统可用内存

32位的进程最大虚拟内存是4G,其中内核空间占1G +用户空间占3G,存在限制

猜想验证

编译一个游戏渠道包,找个32位的设备,安装后。

登录游戏,进入游戏大厅,查看下虚拟内存情况:
在这里插入图片描述
发现虚拟内存Vmsize: 2.9G ,处于正常值。

接着玩几个比较大型的游戏地图:
在这里插入图片描述
再次查看虚拟内存:
在这里插入图片描述
虚拟内存,直线飙升,到3.4G

尝试继续玩不同的地图,也随着记录app的虚拟内存
在这里插入图片描述
在这里插入图片描述
虚拟内存马上接近4G时,线程数任然是192个正常范围,游戏出现黑屏,接着突然闪退。

这时的logcat 输出,线程oom的日志:

2023-06-12 18:29:23.950 23936-24275/? E/Adreno-GSL: <gsl_memory_alloc_pure:2615>: GSL MEM ERROR: kgsl_sharedmem_alloc ioctl failed.
2023-06-12 18:29:23.951 23936-24275/? E/Adreno-GSL: <gsl_memory_alloc_pure:2615>: GSL MEM ERROR: kgsl_sharedmem_alloc ioctl failed.
2023-06-12 18:29:23.953 23936-24275/? E/Adreno-GSL: <gsl_memory_alloc_pure:2615>: GSL MEM ERROR: kgsl_sharedmem_alloc ioctl failed.
2023-06-12 18:29:23.953 23936-24016/? E/AndroidRuntime: FATAL EXCEPTION: miniCrashTask
    Process: com.minitech.miniworld.meta, PID: 23936
    java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
        at java.lang.Thread.nativeCreate(Native Method)
        at java.lang.Thread.start(Thread.java:884)
        at okio.AsyncTimeout.scheduleTimeout(AsyncTimeout.java:88)
        at okio.AsyncTimeout.enter(AsyncTimeout.java:80)
        at okio.AsyncTimeout$2.read(AsyncTimeout.java:235)
        at okio.RealBufferedSource.indexOf(RealBufferedSource.java:354)
        at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:226)
        at okhttp3.internal.http1.Http1Codec.readHeaderLine(Http1Codec.java:215)
        at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:189)
        at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:88)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)

最终,验证了猜想,是32位的app进程存在虚拟内存4G限制,才是导致OOM的罪魁祸首。

总结

在32位cpu架构(armeabi-v7a和armeabi)的设备上或者沙盒环境(不支持64位cpu)的环境下,游戏很大概率会遇到4G虚拟内存限制,从而引发OOM。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值