多进程影响,你的应用退出游戏还会重启吗?真的彻底退出游戏了吗?

Hello,村长

我的场景:

比如我接入某个渠道的 SDK(手游),无论是网游还是单机 SDK,都到都会要求你接入退出回调,如下图所示:
在这里插入图片描述
而再某些场景下,我竟然遇到了这种情况:
1、多进程情况下(配置 android:process="" 属性),点击 ‘退出游戏’ 按钮,游戏并没有退出,反而重新启动游戏

2、多进程 + 多任务栈(配置 android:taskAffinity="com.primer.json.aaaa" 属性),点击 ‘退出游戏’ 按钮,同样的,游戏没有退出成功反而重启

我的解决:

你应该也有一点思路了,我上面提到两种场景,关键词多进程多任务栈

的应用为什么符合多进程呢?我明明没有主动设置多进程!但是,merged Manifest 发现,有个第三方 SDK 的某个 activity,配置了 android:process="" 属性。

主动设置:可以通过 activity 的 android:process="" 属性配置
私有进程:android:process=":primer" 【名称冒号开头】
普通进程:android:process=“primer” 【名称不是冒号开头】
与私有进程的区别?可以了解更多关于 Linux 进程的知识

多任务栈,这个我的应用明确开启了,也就是为 activity 配置 android:taskAffinity=""属性 。

通常,我们退出应用是这样的

private void exit(){
    android.os.Process.killProcess(android.os.Process.myPid());
    System.exit(0);
}

或者是

private void exit(List<Activity> activities){
    for (Activity activity:activities){
        if (activity!=null){
            activity.finish();
        }
    }
    
    activities.clear();
    activities=null;
    
    android.os.Process.killProcess(android.os.Process.myPid());
    System.exit(0);
}

但是,以上两种在我这里没有作用,

所以,我的最终方案是

private void forceExit(Activity activity) {
	   if(activity == null) return;
	   
       ActivityManager ams = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
       if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
           List<ActivityManager.AppTask> appTasks = ams.getAppTasks();
           if (appTasks != null) {
               for (ActivityManager.AppTask item : appTasks) {
                   LogUtil.i(TAG, "appTasks item =" + item.getTaskInfo());
                   item.finishAndRemoveTask();
               }
           }
       }

       List<ActivityManager.RunningAppProcessInfo> mList = ams.getRunningAppProcesses();
       for (ActivityManager.RunningAppProcessInfo info : mList) {
           LogUtil.d(TAG, "info processName = " + info.processName);
           //先 kill 非主进程
           if (info.pid != android.os.Process.myPid()) {
               LogUtil.d(TAG, "info pid = " + info.processName);
               android.os.Process.killProcess(info.pid);
           }
       }
       
	   //我的应用只有一个 activity,如果是有多个,可以存储在一个集合中,循环 finish
       if (activity != null && !activity.isFinishing()) {
           activity.finish();
       }
       
	   //最后 kill 主进程
       android.os.Process.killProcess(android.os.Process.myPid());
       System.exit(0);
   }

最终彻底退出应用

`signal SIGSEGV`(Segmentation Fault)表示程序试图访问它没有权限访问的内存区域,这通常不是“内存泄漏”引起的,而是**非法内存访问**导致的。当程序在初始化为空白(例如空指针、未初始化变量、越界访问等)时出现 `SIGSEGV` 并导致进程退出重启,通常是由于以下原因之一: --- ### 🔍 常见原因分析 1. **解引用空指针(Null Pointer Dereference)** ```c char *ptr = NULL; *ptr = 'a'; // SIGSEGV: 访问非法地址 ``` 2. **使用未初始化的指针** ```c char *ptr; *ptr = 'x'; // ptr 是野指针,指向随机地址 ``` 3. **访问已释放的内存(悬垂指针)** ```c char *ptr = malloc(10); free(ptr); strcpy(ptr, "hello"); // SIGSEGV: 使用已释放内存 ``` 4. **数组/缓冲区越界** ```c int arr[5]; arr[10] = 1; // 越界写入,可能破坏堆栈或触发保护 ``` 5. **栈溢出(如过深递归或大局部数组)** ```c void func() { int big_array[1000000]; // 栈空间不足,导致栈溢出 func(); // 无限递归 } ``` 6. **多线程竞争修改指针(并发问题)** 多个线程同时读写同一指针而无同步机制,可能导致某线程访问已被置空或释放的内存。 7. **函数指针调用错误** ```c void (*func_ptr)() = NULL; func_ptr(); // 调用空函数指针 → SIGSEGV ``` --- ### ✅ 示例代码演示 SIGSEGV ```c #include <stdio.h> #include <stdlib.h> int main() { char *buffer = NULL; // 初始化为空 sprintf(buffer, "Hello"); // 错误:向 NULL 指针写入 return 0; } ``` 运行结果: ``` Program received signal SIGSEGV, Segmentation fault. ``` > 💡 `sprintf` 会尝试写入 `buffer` 所指向的地址,但 `buffer == NULL`,即地址为 0,操作系统禁止访问此区域。 --- ### ✅ 正确做法(修复方式) ```c #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char *buffer = malloc(50); // 分配足够内存 if (buffer == NULL) { fprintf(stderr, "Memory allocation failed\n"); return 1; } strcpy(buffer, "Hello"); // 安全写入 printf("%s\n", buffer); free(buffer); // 释放内存 buffer = NULL; // 避免悬垂指针 return 0; } ``` --- ### ❌ 内存泄漏 vs SIGSEGV 的区别 | 问题类型 | 表现 | 是否导致 SIGSEGV | |----------------|------------------------------|------------------| | 内存泄漏 | 程序占用内存逐渐增长 | 否(长期可能 OOM) | | 悬垂指针/空指针 | 解引用非法地址 | 是 ✅ | | 缓冲区溢出 | 覆盖相邻内存或返回地址 | 可能 ✅ | > ⚠️ 所以你的问题是:**“初始化为空白时出现 SIGSEGV” 更可能是非法内存访问,而不是内存泄漏。** --- ### 🛠 排查工具推荐 1. **GDB(GNU Debugger)** ```bash gcc -g -O0 program.c -o program gdb ./program (gdb) run (gdb) bt # 查看崩溃时的调用栈 ``` 2. **Valgrind(检测非法内存访问)** ```bash valgrind --tool=memcheck --leak-check=full ./program ``` 输出会提示: - Invalid write of size X - Use of uninitialised value - Access not within mapped region 3. **AddressSanitizer(ASan)** ```bash gcc -fsanitize=address -g program.c -o program ./program ``` 直接打印出错位置和类型(如 heap-use-after-free, stack-overflow 等) --- ### 🔒 最佳实践建议 - 初始化所有指针为 `NULL` - 分配内存后检查是否成功 - 使用完后设为 `NULL` - 避免栈上分配过大数组 - 使用安全函数如 `snprintf` 替代 `sprintf` - 开发阶段启用 ASan/Valgrind --- ### 总结 你遇到的 `SIGSEGV` 是因为“初始化为空白”(如空指针)后直接进行了解引用或写入操作,属于典型的**非法内存访问**,与内存泄漏无关。内存泄漏是内存没释放,而 SIGSEGV 是访问了不该访问的地方。 通过调试工具可以快速定位具体哪一行代码出错。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值