首页 > 其他分享 >Unity Android 调用 so 卡死问题 (so 编译踩坑)

Unity Android 调用 so 卡死问题 (so 编译踩坑)

时间:2025-01-11 17:57:23浏览次数:3  
标签:符号 代码 char Unity 循环 so Android 死循环

问题描述
把 Unity 工程编译到 Android 上运行后,出现了一个必现的界面卡死bug。

表现为:每次轮到自己出大招时,必现界面卡死,但程序不会 crash。在 Unity 编辑器和 iOS 下都无法重现。

分析日志发现,卡死前最后调用了算法库中的一个函数。
算法库是 c++ 写的,用 cmake 组织,编译成 so 给 C# 层调用。

定位
怀疑是哪里死循环了。
想试下能否通过工具来定位,使用 Android Studio 的 Thread-Dump 、Unity Attach(死活不成功)发现帮助都不大。
最后还是在算法库里添加了大量日志后,发现在形如下面的代码中死循环!

for(char i = 0;i >=0;–i)
{
i = -1;
printf(“i0 = %d\n”,i);
i += 1;
printf(“i1 = %d\n”,i);
}
上面代码合理应该输出 -1,0 ,结束循环。
然而,在 Android 下却死循环了!结果是 255,0,255,0,255,…,感觉像是溢出后回环了

分析
google 一下发现:
在 x86 下,char 默认是 有符号。
在 ARM 架构下,char 默认是 无符号,即 Android 这种情况。i = 0,–i 变成 -1,无符号下就是 1111 1111 = 255,再+1就溢出了,变成0,无限循环。
而 iOS 虽然也是 ARM 架构,但它的 char 默认却是有符号的,所以也没出问题。

死循环代码快速定位方法

定位死循环代码可以是一个挑战,尤其是在大型项目中。以下是一些快速定位死循环的有效方法和工具,帮助你更高效地找到问题所在:

1. 使用日志记录

  • 添加日志:在循环的关键位置添加日志输出,记录循环的迭代次数和变量的状态。这可以帮助你确定循环是否在按预期运行。

    for (int i = 0; i < MAX_ITERATIONS; ++i) {
        printf("Iteration: %d\n", i);
        // 其他逻辑
    }
    
  • 条件日志:在循环中添加条件日志,记录特定条件下的变量值,以便更好地理解循环的行为。

2. 使用调试器

  • 设置断点:在循环的开始和结束处设置断点,观察变量的变化。如果循环没有正常结束,可以逐步调试,查看变量的状态。

  • 观察变量:在调试器中观察循环变量的值,查看它是否在预期范围内变化。

3. 使用线程转储(Thread Dump)

  • 生成线程转储:在 Android Studio 或其他 IDE 中生成线程转储,查看当前线程的状态。死循环的线程通常会在某个位置反复执行相同的代码。

  • 分析堆栈:分析线程堆栈,查找循环的调用栈,确定死循环的具体位置。

4. 使用静态分析工具

  • 静态分析:使用静态分析工具(如 Clang-Tidy、Cppcheck)来检查代码中的潜在问题。这些工具可以帮助识别可能导致死循环的代码模式。

5. 代码审查

  • 同行审查:让其他开发者审查你的代码,可能会发现你自己未注意到的问题。不同的视角可能会帮助识别潜在的逻辑错误。

6. 使用时间限制

  • 超时机制:在循环中添加超时机制,如果循环运行超过预定时间,则输出警告并退出。这可以帮助你在开发过程中快速发现死循环。

    auto start = std::chrono::high_resolution_clock::now();
    while (condition) {
        // 循环逻辑
        auto now = std::chrono::high_resolution_clock::now();
        if (std::chrono::duration_cast<std::chrono::seconds>(now - start).count() > TIME_LIMIT) {
            printf("Loop exceeded time limit!\n");
            break;
        }
    }
    

通过结合这些方法,你可以更快速地定位和解决死循环问题。希望这些建议对你有所帮助!如果你有其他问题或需要进一步讨论的内容,欢迎继续交流!

问题背景

在 Android NDK 开发中,char 类型的符号性可能会因平台而异。在 x86 架构上,char 默认是有符号的,而在 ARM 架构上,char 默认是无符号的。这种差异可能导致在某些情况下出现意想不到的行为,例如所遇到的死循环问题。

解决方案

  1. 使用 CMake 显式指定 char 符号性

    • 在 CMakeLists.txt 文件中,可以通过添加编译选项来确保 char 被视为有符号类型。可以在 CMake 文件中添加以下行:
    add_compile_options(-fsigned-char)
    

    或者,如果你使用的是 target_compile_options,可以这样写:

    target_compile_options(your_target_name PRIVATE -fsigned-char)
    
  2. 使用 CMake 的 CMAKE_C_FLAGSCMAKE_CXX_FLAGS

    • 你也可以直接在 CMakeLists.txt 中设置全局的 C 和 C++ 编译标志:
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsigned-char")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsigned-char")
    

其他建议

  • 使用标准类型

    • 为了避免与平台相关的类型问题,建议使用 C++ 标准库中的固定宽度整数类型,如 std::int8_tstd::uint8_t。这些类型在所有平台上都是一致的,能够避免因符号性引起的问题。
  • 编写文档

    • 在项目文档中记录下关于 char 符号性的注意事项,特别是在跨平台开发时,帮助团队成员理解潜在的陷阱。
  • 测试和验证

    • 在不同平台上进行充分的测试,确保代码在所有目标平台上都能正常工作。可以使用 CI/CD 工具来自动化这一过程。
  • 代码审查

    • 在代码审查过程中,特别注意数据类型的使用,确保在跨平台代码中使用了合适的类型。

通过这些方法,可以有效减少因数据类型符号性引起的问题,提高代码的可移植性和稳定性。如果你有其他问题或需要进一步讨论的内容,欢迎继续交流!

标签:符号,代码,char,Unity,循环,so,Android,死循环
From: https://blog.csdn.net/qq_33060405/article/details/144995101

相关文章

  • Windows下Dll在Unity中使用的一般方式
    Windows下Dll在Unity中使用的一般方式Unity中虽然已经有广泛的库和插件,但是相较于C++的库生态而言,还是有一定的差距;因此本篇博文记录Windows下将C++函数打包成动态链接库在Unity中使用的一般方法。环境VisualStudio2019,Unity2022,Windows11,OpenCV说明Unity中有针对Wind......
  • 最新版Firefox浏览器加载ActiveX控件之SolidWorks 3D控件
     背景   SolidWorks ComposerPlayer是一个免费应用程序,它允许内容创作者将Composer内容分发给任何最终用户。ComposerPlayer与Composer一样具有高性能。ComposerPlayer绝不仅仅是一个简单的查看器,内容使用者可以在产品可交付内容中获得深入的互动体验。 ......
  • Unity URP Shader Graph 实现复古电视机效果
    想到一出实现一出的复古电视机效果实现。复古电视机效果显示展示:使用素材一张纹理需要放映的图片,一张遮罩贴图,一个电视机模型。UV使用Spherize模拟电视机球状显示屏。扫描线A效果扫描线B效果像素化/随机UV偏移屏幕做旧效果边缘变暗效果屏幕黑边效果自制一张合适......
  • 请说说鸿蒙和android有什么区别?
    鸿蒙与Android在前端开发方面的区别主要体现在以下几个方面:开发框架和语言:鸿蒙使用ArkTS语言,结合ArkUI声明式UI框架进行开发,提供了一套全新的组件和布局系统,更易于构建跨设备的应用。Android则主要使用Java或Kotlin语言,搭配AndroidSDK进行开发,UI布局使用XML,近年来也支持Jet......
  • C#中简单Socket编程
    引言Socket编程是网络编程的基础,通过Socket编程,可以实现计算机之间的通信。本文将介绍如何在C#中进行简单的Socket编程,包括服务器端和客户端的实现。示例将展示TCP连接的基本操作,适用于理解网络通信的基本概念和实现方法。准备工作确保您的开发环境中安装了.NETSDK,可以通过Vis......
  • Android 14.0 app调用hal层接口功能实现系列一(hal接口的创建)
    1.前言在14.0的系统rom定制化开发中,对于一些需要在app中调用hal层的一些接口来实现某些功能而言,就需要打通app到hal的接口,实现功能需求,这一节首先讲在hal层中提供接口然后通过jni来调用,首先来建立hal层的相关接口和c++文件,提供hal层供上层调用的接口2.app调用hal层接口功能实......
  • 2024-12-10-json
    Json在pox.xml中添加如下依赖<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.78</version></dependency>添加上述依赖后可用于接收传输过来的请求体数据......
  • 轻松实现单点登录(SSO):基于 Keycloak 的 OIDC 与 OAuth 2.0 完整指南
    言简意赅的讲解KeycloakOIDC与OAuth2.0解决的痛点Keycloak是一款开源的身份和访问管理(IAM)工具,支持多种协议,包括OIDC(OpenIDConnect)、OAuth2.0、SAML等。它简化了身份认证与授权流程,提供了集中管理用户、角色、权限等功能,常被用作企业或微服务体系下的统一认证中心......
  • Some kinds of vertex colorings and some results
    Wewillintroducesomekindsofvertexcolorings,whicharemymainresearchtopicsoverthepastfiveyears.propervertexcoloringofgraphs.AcyclicColoringSomeexamplesofpropercoloringandacycliccoloringaregivenasfollows.ListCo......
  • 3. ur3+robotiq ft sensor+robotiq 2f 140+realsense d435i配置rviz,gazebo仿真环境
    原文地址:ur3+robotiqftsensor+robotiq2f140+realsensed435i配置rviz,gazebo仿真环境ur3+robotiqftsensor+robotiq2f140+realsensed435i配置rviz,gazebo仿真环境搭建环境:ubuntu:20.04ros:Noneticsensor:robotiq_ft300gripper:robotiq_2f_140_gripperUR:UR3reasens......