究竟是什么导致Android中的"旋转暂停"错误?

 大印文化 发布于 2023-02-08 06:22

我目前无法调试一些依赖本机库的Android代码.特别是一个本地调用似乎容易出现"旋转暂停"错误.它通常表现如下:

threadid=2: spin on suspend #2 threadid=48 (pcf=3)

到目前为止,我还没有确切地确定这里失败了什么,除了在大约10条消息之后,我的应用程序遇到了SIGSTKFLT退出.每次,第一个线程是GC,第二个线程是当前正在执行本机代码的线程.与此消息一起打印的堆栈部分始终在堆栈顶部具有本机方法.

当Dalvik抱怨这件事时究竟发生了什么,我怎样才能开始调试原因以便我能解决它?

编辑:一个有趣的皱纹 - 在本机开发人员做了一些更改后,我现在也看到以下错误:

PopFrame missed the break
VM aborting
Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1)

对我来说,线程转储在堆栈顶部显示我的本机方法也是非常奇怪的,但是线程状态RUNNABLE不是NATIVE- 这怎么可能呢?

1 个回答
  • 基本问题是Dalvik是一个安全点挂起VM,并使用"停止世界"垃圾收集.这意味着,要使GC运行,它必须等待所有线程到达可以确保它们不会改变堆的点.

    由于某种原因,您的一个线程没有响应GC线程的暂停请求.它实际上并没有在本机代码中执行; 如果是的话,线程将处于NATIVE状态,这被认为是安全的.(对本机堆的所有访问都通过JNI调用进行门控,并且所有JNI调用都会执行挂起检查.)

    出于性能原因,JIT能够以跳过挂起检查的方式将编译代码块链接在一起.如果一个线程需要很长时间来挂起,挂起线程将"解锁"块,并等待一段时间.最终它开始抱怨,并最终 - 它最终放弃并中止VM.

    有些设备使用供应商修改的Dalvik版本会出错,并且在紧密循环中可能会发生中止.在这种情况下,我不希望在堆栈顶部看到本机方法.

    调试的最佳选择是在不满意的时候附加gdb并尝试弄清楚目标线程正在做什么.本机代码可能以某种方式破坏VM状态或返回堆栈,因此从本机代码返回时,线程会被卡住.

    编辑后更新:dvmPopFrame()函数用于从托管堆栈弹出堆栈帧.当VM调用您的本机方法时,它会插入一个"中断"帧,这样当堆栈展开以进行异常处理时,VM不会通过调用站点.(它也用于VM发出的托管代码方法调用,例如用于反射或<clinit>.)消息PopFrame missed the break表示未找到中断帧.

    中断帧具有空方法指针.展开堆栈时,只要dvmPopFrame()看到非空方法指针(意味着它不是中断帧)和非空前一帧指针(意味着你没有到达堆栈顶部),dvmPopFrame()就会继续.如果你点击堆栈顶部,你就错过了休息 - 所有Dalvik堆栈都以一个真正的方法开始(如果线程通过JNI连接到VM,有时候是"假"方法).

    所以我的猜测是本机代码破坏了堆栈,使前一帧指针归零.将此排序的一种技术是让VM调用一个调用实际本机方法的本机方法; "中间人"在堆栈上分配一些东西,将其设置为已知值,调用实际方法,然后在返回之前验证其堆栈分配是否未更改.

    (可能需要使用这些值来阻止编译器优化它们;如果使用类似的东西:

    if (jniEnv == NULL) {
        printf("my stuff is ...", ...);
    }
    

    然后它永远不会真正运行,因为它永远不会JNIEnv*为空...但编译器不知道.)

    有关Dalvik堆栈布局的完整说明,请参阅dalvik/vm/interp/Stack.h.

    RUNNABLE从本机代码返回时,线程是正常的.您的本机方法仍然位于顶部,因为弹出它的代码失败并中止了VM.

    2023-02-08 06:50 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有