一、前言

在大型 C++ 工程(例如 Chrome 浏览器内核)中,开发者经常会遇到这样的选择:
到底应该在关键点使用 CHECK 直接崩溃,还是使用 returnLOG 记录错误然后继续执行?

这看似只是一个代码风格问题,实则背后牵扯到 线上崩溃率、稳定性、用户体验、以及问题定位效率

本文结合浏览器内核的真实代码案例,从源码设计出发,分析 CHECKreturn 的差异,探讨它们在 稳定性优化线上质量保障 中的取舍,并给出一些落地的优化实践经验。


二、背景知识:什么是 CHECK

在 Chromium 基础库(base/check.h)中,CHECK 是一个类似于断言的宏,用法非常常见:

CHECK(pointer); CHECK_EQ(size, expected_size); 

DCHECK 不同的是:

  • CHECK 永远生效(无论 Debug 还是 Release),失败时会直接触发 致命崩溃(调用 ImmediateCrash())。

  • DCHECK 只在 Debug 或启用了 --enable-dcheck 的模式下才有效,Release 默认不生效。

也就是说:

  • CHECK = 防御型编程 + 线上崩溃

  • DCHECK = 调试模式下的保护网

因此,使用 CHECK 的地方,意味着开发者明确认为 “如果条件不满足,继续运行程序只会带来更大风险,还不如直接崩溃并上报”。


三、典型代码案例分析

以浏览器 UI 初始化的一个场景为例:

ViewBuilder buildui; const ui::ThemeProvider* tp = GetThemeProvider(); if (tp) { base::RefCountedMemory* memory = tp->GetRawData("browser.xml", ui::k100Percent); CHECK(memory); if (memory) { buildui.BuilderUiUtf8((const char*)(memory->front()), this); } } 

3.1 为什么这里要用 CHECK?

  • browser.xml 是浏览器 UI 布局的核心资源,缺失后界面几乎无法正常渲染。

  • 如果 memory == nullptr,继续运行只会导致后续逻辑 不可控,甚至触发 更隐蔽的崩溃

  • 与其后面某处 随机崩溃,不如在这里立刻崩溃并生成明确的堆栈。

这就是 “快速失败(fail fast)” 的思想。

3.2 如果换成 return,会发生什么?

假设我们改成:

if (!memory) { LOG(ERROR) << "browser.xml not found!"; return; } 

那么结果可能是:

  1. 浏览器启动后黑屏、空白 UI,但进程没崩溃。

  2. 用户上报 “浏览器打不开界面”,但 crash dump 无法收集到。

  3. 问题变成 用户可见 bug,而不是 研发可复现的崩溃

这对于稳定性指标(crash 率下降),看似有好处,但实际上可能导致 用户体验更差,研发也更难排查问题。


四、崩溃率 vs 稳定性:Return 和 CHECK 的权衡

在工程实践中,我们必须明确:

  • 崩溃率降低 ≠ 稳定性提升

  • 关键在于 是否能继续安全执行

我们来对比:

场景使用 CHECK使用 return
必要资源缺失(如 ICU 数据、核心 UI XML)立即崩溃,易于定位问题可能黑屏、功能残缺,用户可见异常
可选功能缺失(如某个实验性模块文件)不建议 CHECK,影响整体稳定性return 更合理,降级执行
开发/调试阶段CHECK 更利于暴露问题return 可能掩盖 bug
线上用户体验崩溃率升高,定位快崩溃率降低,但潜在 bug 难发现

所以,CHECKreturn 的取舍,本质是 在开发效率和用户体验之间做平衡


五、实战案例:ICU 数据初始化

再看一个浏览器启动过程的例子:

bool InitializeICUFromDataFile() { LazyInitIcuDataFile(); bool result = InitializeICUWithFileDescriptorInternal(g_icudtl_pf, g_icudtl_region); // 省略修复逻辑... #if !BUILDFLAG(IS_CHROMEOS) CHECK(result); #endif return result; } 

5.1 为什么要 CHECK(result)

ICU(International Components for Unicode)库是浏览器处理多语言文本的底层依赖:

  • URL 编解码

  • 字符串归一化

  • 字体渲染

如果 result == false,意味着 ICU 数据加载失败,浏览器将 无法正常显示文字,后续所有逻辑都是“废的”。

这种情况不可能通过 return 优雅降级,因此必须 硬崩溃

5.2 线上优化的方式

有些厂商会加 修复逻辑

  • 如果文件损坏,尝试复制备份文件或重新下载。

  • 只有在修复仍失败时,才触发 CHECK

这样既保留了问题定位能力,也避免了因文件损坏导致的大规模崩溃。


六、Return vs CHECK 的取舍标准

结合浏览器内核开发经验,我总结了一套实践标准:

  1. 核心依赖缺失(必须)

    • 比如 ICU、核心 DLL、主进程资源

    • 必须 CHECK,否则继续执行毫无意义

  2. 关键路径但可恢复(尝试修复后 CHECK)

    • 比如 UI skin、配置文件

    • 可以先尝试 fallback/修复,最后再 CHECK

  3. 非关键路径(直接 return)

    • 比如实验性模块、日志收集、辅助功能

    • return 避免线上崩溃率增加

  4. Debug 阶段优先 CHECK,Release 阶段视情况降级

    • 开发时暴露问题

    • 发布时保障用户体验


七、稳定性优化的工程思考

7.1 崩溃率指标要结合 “可用性”

  • 单纯追求 crash 率下降 并不科学

  • 更重要的是用户是否能 完成主要功能

  • 如果 return 导致浏览器无法启动,虽然 crash 率下降,但用户留存反而下降

7.2 崩溃收敛要和监控系统结合

  • 通过 CrashpadBreakpad 收集崩溃堆栈

  • 配合日志系统判断是 偶发 bug 还是 环境问题

  • 对于外部文件缺失类问题,可以考虑 自愈机制(repair)

7.3 CHECK 的位置很关键

  • CHECK 应该放在 错误首次被发现的位置,而不是后面调用处

  • 否则会让堆栈看起来和实际问题无关,增加排查难度


八、总结

本文通过分析 CHECKreturn 的区别,结合浏览器内核中的 UI 资源加载ICU 初始化 两个案例,说明了它们在 线上崩溃率优化 中的不同作用:

  • CHECK:快速失败,便于定位核心问题,但可能提高 crash 率

  • return:避免崩溃,提升稳定性,但可能掩盖严重问题

最佳实践是:

  • 核心依赖:必须 CHECK

  • 可修复:修复失败后 CHECK

  • 非关键路径:return

崩溃率优化的目标不只是数字下降,而是 既能快速定位问题,又能保障用户体验

这正是工程实践中的智慧所在。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96420.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96420.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/96420.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构与算法Trip第3站】双指针

我们来详细讲解一下算法中非常常用且重要的技巧——双指针法。 这是一个概念清晰但应用极其广泛的技术&#xff0c;掌握它能帮助你高效解决许多问题。 一、什么是双指针法&#xff1f; 核心思想&#xff1a;顾名思义&#xff0c;就是在遍历对象&#xff08;通常是数组或链表&am…

时序数据库选型指南:基于大数据视角的IoTDB应用优势分析详解!

目录 一、时序数据库选型的基本原则 1.1 数据特征与需求分析 1.1.1 数据规模与写入负载 1.1.2 查询需求 1.1.3 数据保留与归档策略 1.1.4 系统扩展性与高可用性 1.2 技术架构与系统性能评估 1.2.1 写入性能 1.2.2 查询性能 1.2.3 数据压缩能力 1.2.4 高可用性与灾备…

缓存三大劫攻防战:穿透、击穿、雪崩的Java实战防御体系(三)

第三部分&#xff1a;缓存雪崩——大量key失效引发的“系统性崩溃” 缓存雪崩的本质是“大量缓存key在同一时间失效&#xff0c;或缓存集群整体故障”&#xff0c;导致请求全量穿透至DB&#xff0c;引发“系统性崩溃”。 案例4&#xff1a;电商首页的“批量过期”灾难 故障现场…

解决docker配置了镜像源但还会拉取官方镜像源的问题

&#x1f3d3;我们有时候虽然配置了Docker国内镜像源&#xff0c;但是还是会绕过去请求官方镜像源&#xff08;docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded&#xff09;&#xff0c;现在我们就来解决一…

R语言水文、水环境模型优化:从最速上升法、岭分析到贝叶斯优化与异方差处理,涵盖采样设计、代理模型与快速率定等

在水利工程、环境治理、生态保护、机械设计与航天航空等现代工业与科学领域&#xff0c;数学模型已成为不可或缺的核心分析、预测与决策工具。然而&#xff0c;随着系统复杂性的日益增长&#xff0c;模型构建的精确性、参数率定的效率以及不确定性量化的重要性被提到了前所未有…

关于数据采集与处理心得(一)

目前所实践的经验告知我&#xff01;1. 别企图妄想一个脚本解决所有问题要学会对问题分解&#xff0c;编写多个脚本一步步将问题解决&#xff0c;如果每一个步骤都为了下一个阶段的成果打地基&#xff0c;也是非常OK的。同时要尽可能将每一个编写的脚本都尽到最大的利用率2. 编…

IvorySQL 适配 LoongArch® 龙架构

IvorySQL 社区很高兴向您宣布&#xff0c;IvorySQL 已成功适配LoongArch 龙架构&#xff0c;为国产数据库与国产芯片的深度融合迈出了坚实一步。这一里程碑标志着 IvorySQL 在推动国产化生态建设、赋能信创产业方面取得了重大突破&#xff0c;为用户提供更高效、稳定、安全的数…

数据库分库分表是考虑ShardingSphere 还是Mycat?

http://www.mycat.org.cn/ https://shardingsphere.apache.org/ 这是一个非常核心且优秀的问题。在选择 ShardingSphere 和 Mycat 之间&#xff0c;对于游戏这种高性能、高复杂度的场景&#xff0c;目前行业内的主流选择和发展趋势毫无疑问是 ShardingSphere。 我会为你详细对…

mysql分库分表数据量核查问题

场景&#xff1a; 使用分库分表的业务有时分库数量几百甚至上千&#xff0c;当主管需要查询每个库中的数据&#xff0c;掌握数据分布情况。要你查看哪些库中的表数量大于某个量级的给找出来 &#xff0c;你会怎么做。 例子 &#xff1a; mysql库数量&#xff1a;db_xx_devicein…

python之socket网络编程

引言 在互联网时代&#xff0c;网络编程已经成为开发人员必备的技能之一。无论是Web开发、实时通信还是分布式计算&#xff0c;都离不开网络编程的支持。Python提供的socket模块为我们提供了简洁而强大的接口&#xff0c;可以轻松实现客户端和服务器之间的通信。 Socket编程是网…

WPF Telerik.Windows.Controls.Data.PropertyGrid 自定义属性编辑器

1.AI帮忙定义新用户控件 2.在属性上添加TelerikEditorAttribute特性 private ObservableCollection<string> _axisOrder;[Display(Description "点位", GroupName "通用", Name "轴&顺序", Order 1)][DataMember][TelerikEditorAt…

【超详细】别再看零散的教程了!一篇搞定Gitee从注册、配置到代码上传与管理(内含避坑指南最佳实践)

&#x1f525;个人主页&#xff1a;艾莉丝努力练剑 ❄专栏传送门&#xff1a;《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C基础知识知识强化补充、C/C干货分享&学习过程记录 &#x1f349;学习方向&#xff1a;C/C方向学习者…

43.shell脚本循环与函数

shell脚本循环与函数 for 循环 for 循环用于一次性读取多个信息&#xff0c;逐一对信息进行操作处理&#xff0c;特别适合处理有范围的数据 语法 for 变量名 in 取值列表 do命令序列 done批量创建用户 #!/bin/bashtouch /root/users.txt echo aka blues cloe dio foks > /ro…

模型部署:(四)安卓端部署Yolov8-v8.2.99实例分割项目全流程记录

模型部署&#xff1a;&#xff08;四&#xff09;安卓端部署Yolov8-v8.2.99实例分割项目全流程记录1、下载ncnn2、下载opencv-mobile3、文件拷贝4、andorid_studio相关配置5、文件内参数设置5、重构项目&#xff1a;6、打包apk7、部署自己训练的实例分割模型1、下载ncnn 地址&…

高并发、低延迟全球直播系统架构

一、 核心架构图 整个系统的数据流和工作流程如下图所示&#xff0c;它清晰地展示了从主播推流到观众观看的完整过程&#xff1a; #mermaid-svg-QzNpj0DWxd5FERPC {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-QzN…

AWS strands agents 当智能体作为独立服务/容器部署时,它们无法共享进程内状态

当智能体作为独立服务/容器部署时&#xff0c;它们无法共享进程内状态。 以下是针对分布式部署中动态内存库的生产就绪解决方案&#xff1a;1. 基于外部存储的内存库基于 DynamoDB 的共享内存import boto3 from strands import Agent, tool from typing import Dict, Any impor…

第五节 JavaScript——引用类型、DOM/BOM 与异步编程

JavaScript 的第五节课通常会深入探讨 ​​引用类型、DOM 操作、BOM 操作、事件处理以及异步编程​​ 等核心概念。这些知识能让你创建动态交互丰富的网页。下面我将详细讲解这些内容并提供示例。 🚀 JavaScript 第五节:引用类型、DOM/BOM 与异步编程 ⚡ 一、引用类型 引…

使用Pycharm进行远程ssh(以Featurize为例)

使用Pycharm进行远程ssh&#xff08;以Featurize为例&#xff09;文章目录介绍应用背景远程连接Python连接Jupyter介绍应用背景 在使用Pycharm 专业版的时候进行远程ssh连接服务器&#xff08;Featurize&#xff09;的Python解释器和Jupyter 远程连接Python 打开Pycharm点击…

深入研究:ClickHouse中arrayExists与hasAny在ORDER BY场景下的性能差异

最近公司大数据情况下ClickHouse查询性能极差&#xff0c;后来发现在大数据量ORDER BY场景下&#xff0c;arrayExists(x -> x in ...)比hasAny性能快10倍&#xff01;&#xff01;&#xff01;&#xff01; 一、问题重述与研究背景 在大数据量 ORDER BY场景下&#xff0c;…

Spring AI (二)结合Mysql做聊天信息存储

上文讲了&#xff0c;用Spring ai做简单的聊天功能&#xff0c;没看过的可以查看下 Spring AI结合豆包模型 这里简单结合下Jdbc做下聊天记录的存储和查询&#xff0c;让对话变的更智能。 首先是Pom的支持 <dependency><groupId>org.springframework.ai</grou…