ANR之RenderThread不可中断睡眠state=D

text 复制代码
 
"main" prio=5 tid=1 Native
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x71db4b38 self=0xb40000770ebf27b0
  | sysTid=26519 nice=0 cgrp=foreground sched=0/0 handle=0x789581f4f8
  | state=S schedstat=( 189056125728 54507506891 540673 ) utm=12710 stm=6195 core=1 HZ=100
  | stack=0x7feb3d3000-0x7feb3d5000 stackSize=8192KB
  | held mutexes=
  native: #00 pc 000000000004b4cc  /apex/com.android.runtime/lib64/bionic/libc.so (syscall+28)
  native: #01 pc 000000000004f0b4  /apex/com.android.runtime/lib64/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+144)
  native: #02 pc 00000000000af2b4  /apex/com.android.runtime/lib64/bionic/libc.so (pthread_cond_wait+60)
  native: #03 pc 0000000000221054  /system/lib64/libhwui.so (android::uirenderer::renderthread::DrawFrameTask::postAndWait()+252)
  native: #04 pc 0000000000204c60  /system/lib64/libhwui.so (android::android_view_ThreadedRenderer_syncAndDrawFrame(_JNIEnv*, _jobject*, long, _jlongArray*, int)+84)
  at android.graphics.HardwareRenderer.nSyncAndDrawFrame(Native method)
  at android.graphics.HardwareRenderer.syncAndDrawFrame(HardwareRenderer.java:433)
  at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:658)
  at android.view.ViewRootImpl.draw(ViewRootImpl.java:4117)
  at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3844)
  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3115)
  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1959)
  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8191)
  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
  at android.view.Choreographer.doCallbacks(Choreographer.java:796)
  at android.view.Choreographer.doFrame(Choreographer.java:731)
  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
  at android.os.Handler.handleCallback(Handler.java:938)
  at android.os.Handler.dispatchMessage(Handler.java:99)
  at android.os.Looper.loop(Looper.java:223)
  at android.app.ActivityThread.main(ActivityThread.java:7705)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1001)
  
  
  "RenderThread" daemon prio=7 tid=2 Native
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x131c1dc0 self=0x770ebf96f0
  | sysTid=26814 nice=-4 cgrp=foreground sched=0/0 handle=0x759001ecc0
  | state=D schedstat=( 169545217808 59675325470 756224 ) utm=10233 stm=6720 core=1 HZ=100
  | stack=0x758ff27000-0x758ff29000 stackSize=995KB
  | held mutexes=
  native: (backtrace::Unwind failed for thread 26814: Thread has not responded to signal in time)
  (no managed stack frames)

从 Android 系统线程的正常工作特性和该RenderThread的实际状态对比来看,此线程完全不正常,处于 "深度阻塞 + 高负载" 状态,是导致应用 ANR 的核心中间环节。以下从线程状态、耗时、调试信息三个维度拆解异常点:

一、先明确 RenderThread 的 "正常定位"

RenderThread是 Android 应用的专属渲染线程 (后台守护线程,daemon=true),职责是:

  1. 执行 UI 绘制指令(如 OpenGL ES 调用、图层合成、纹理加载);
  2. 与 GPU、显示驱动交互,完成 "主线程下发的渲染任务";
  3. 正常状态下应是 "短时运行 + 可调度 "------ 即大部分时间处于S(可中断睡眠,等待主线程的渲染指令)或R(运行态,执行渲染计算),且累计耗时与应用运行时间匹配(如运行 10 分钟,耗时通常几秒钟)。

二、此 RenderThread 的 3 个核心异常点

1. 线程状态state=D:不可中断睡眠(致命异常)

  • state=D的含义 :Linux 线程状态中的 "Uninterruptible Sleep(不可中断睡眠)",表示线程正在等待某个必须完成的资源 / 操作 (如硬件 IO 响应、内核锁释放、GPU 驱动反馈),此时即使系统发送调试信号(如SIGQUIT)也无法唤醒线程,只能等待资源就绪。

  • 正常 RenderThread 的状态

    • 等待渲染指令时:state=S(可中断睡眠,主线程下发指令后可立即唤醒);
    • 执行渲染计算时:state=R(运行态,短时占用 CPU/GPU);
  • 此线程的异常性state=D意味着 RenderThread "卡死后完全无响应"------ 既无法接收主线程的新渲染指令,也无法继续处理已有的渲染任务,直接导致主线程(等待渲染同步)阻塞。

2. 调度耗时schedstat:超 200 秒累计耗时 + 高内核态占比(严重负载异常)

schedstat字段格式:(用户态耗时ns, 内核态耗时ns, 被调度次数),换算后:

指标 数值(换算后) 正常范围(前台应用) 异常分析
累计用户态耗时 169545217808ns ≈ 169s 与应用运行时间匹配(如 10 分钟运行≈5s) 用户态耗时高:说明线程频繁执行渲染计算(如列表项绘制、图片解码),但因 CPU 被抢占(其他进程占 44% CPU),计算过程被反复打断,耗时被拉长;
累计内核态耗时 59675325470ns ≈ 59.7s 通常占总耗时的 5%-10% 内核态耗时占比 30%(59.7/229.2):说明线程频繁调用内核接口(如 GPU 驱动交互、显存分配),且每次调用都被阻塞(如 GPU 忙、驱动响应慢),属于 "内核级阻塞";
被调度次数 756224 次 运行 10 分钟≈1-2 万次 调度频繁但执行效率极低:每次被调度后,要么因 CPU 不足无法执行,要么因等待硬件资源(GPU)再次进入阻塞,导致 "调度次数多但实际渲染进度慢"。

3. Backtrace Unwind 失败:线程无响应调试信号(深度阻塞)

  • 正常情况 :Android ANR 文件会打印RenderThreadnative调用栈(如调用了libGLESv2_adreno.so(GPU 驱动库)、libhwui.so(Android 渲染库)的哪些函数),帮助定位具体阻塞点(如卡在 "GPU 纹理上传" 还是 "图层合成");
  • 此线程的异常backtrace::Unwind failed for thread 26814: Thread has not responded to signal in time------ 系统尝试发送SIGQUIT信号获取线程栈,但线程处于state=D(不可中断),完全无法响应信号,导致 "无法定位具体阻塞的渲染步骤";
  • 隐含问题state=D下的线程不仅 "无法处理业务任务(渲染)",连 "调试信号" 都无法响应,属于深度无响应状态,是线程阻塞的极端情况。

三、异常的连锁影响:直接导致主线程阻塞

结合之前 ANR 分析的 "主线程卡在syncAndDrawFrame"(等待渲染同步),此RenderThread的异常会形成 "死等链":

  1. 主线程在MusicPlayingListActivity下发 "列表渲染指令" 给RenderThread
  2. RenderThread因 "CPU 被抢占 + GPU 资源忙" 进入state=D,无法执行渲染;
  3. 主线程需等待RenderThread完成渲染后才能调用syncAndDrawFrame同步结果,导致主线程被 "卡死";
  4. 主线程被卡死→无法处理用户的DOWN触摸事件→等待 5 秒后触发 "输入分发超时 ANR"。

四、总结:此 RenderThread 的异常性质

它不是 "正常负载高",而是 "阻塞性异常"------ 核心问题不是 "渲染任务多",而是 "任务无法被执行(CPU/GPU 资源被抢占)+ 线程自身陷入不可中断状态",最终成为 ANR 的 "关键导火索"。

相关推荐
tq10863 分钟前
学习Hilt注解
android
2501_9159214326 分钟前
iOS 应用代上架流程,多工具组合与使用 开心上架 跨平台自动化上传指南
android·ios·小程序·uni-app·自动化·cocoa·iphone
日日行不惧千万里31 分钟前
2025最新仿默往 IM 即时通讯系统源码(PC + Web + iOS + Android)完整版发布!
android·ios
歪歪10031 分钟前
React Native开发Android&IOS流程完整指南
android·开发语言·前端·react native·ios·前端框架
雪芽蓝域zzs37 分钟前
uniapp 修改android包名
android·uni-app
用户2018792831671 小时前
厨房里的协程大冒险:launch与async的烹饪之旅
android
用户2018792831671 小时前
浅析协程与挂起函数实现原理
android
木易士心2 小时前
Android Handler 机制原理详解
android·app
用户2018792831672 小时前
CoroutineDispatcher的"自由精灵" - Dispatchers.Unconfined
android
用户2018792831672 小时前
用 “奶茶连锁店的部门分工” 理解各种 CoroutineScope
android