普通视图
iOS 26 开始强制 UIScene ,你的 Flutter 插件准备好迁移支持了吗?
斑马思维机的详细调研
本文档创建于 2025.3,最后更新于 2025.10
一、产品介绍
斑马思维机是针对 2-8 岁儿童的全科启蒙学习机。由在线教育集团“猿辅导”旗下的斑马品牌在 2022 年 11 月推向市场,并在 2023 年 8 月升级为二代产品:斑马思维机 G2。
它包含语文、思维、英语、音乐等学科内容,通过纸质的题卡结合点触交互的形式,让孩子在不同情景主题场景下互动,通过互动答题的形式,完成内容的教学。插卡自动出题,孩子通过点触答题。答对有鼓励,答错会有提醒,孩子可以自主完成从插卡到答题的整个过程。
相比别的早教学习机,斑马思维机的核心特点是没有传统的屏幕。它用纸质题卡来完成学习交互,在完成学习的同时可以有效保护低幼孩子的眼睛,防止过早接触电子屏幕产生沉迷。
产品上线后累计销量突破 100 万台,2023 年和 2024 年连续两年全国销量第一。
斑马思维机主要具备如下产品优势:
1、专业教研
团队邀请了三位行业专家共同参与内容研发,分别是:
- 曹立宏教授:中国传媒大学的脑科学专家。
- 刘嘉教授:清华大学心理学专家。同时也是“最强大脑”节目的科学总顾问。
- 蔡可教授:首都师范大学教育学专家。同时也是语文新课标的制定者。
在以上专家参与的同时,斑马结合自己斑马 AI 学产品的 3000 万用户的 100 亿次线上作答数据,为题卡的编制提供大数据支撑。
斑马思维机题卡构建了科学合理的分级进阶体系,分设 S0、S1、S2、S3 4 个难度级别。这种设置充分考虑了 2-8 岁儿童不同阶段的认知水平和思维发展能力。题卡难度逐阶递增、螺旋上升,能够循序渐进地开发儿童大脑潜能。
2、纸屏护眼
不同于传统有屏幕的学习机,斑马思维机通过插卡+点触的方式来学习,可以有效减少孩子接触电子屏幕的时间,防止孩子过早接触屏幕,影响视力。
每张题卡上都有丰富的主题元素,帮助孩子建立起学习的兴趣。
每张纸质题卡都用了食品级白卡和大豆油墨印刷,保证对孩子安全。
3、全科启蒙
斑马思维机的题卡包含语文、思维、英语三大核心题卡,相关的内容体系分为 S0、S1、S2、S3 4 个难度级别,且难度分级科学合理,充分满足不同年龄段孩子的学习需求。其中:
| 级别 | 针对年龄 | 培养重点 |
|---|---|---|
| S0 | 2-3 | 习惯养成 |
| S1 | 3-4 | 兴趣培养 |
| S2 | 4-5 | 知识积累 |
| S3 | 5+ | 应用拓展 |
4、无限扩展
斑马思维机的题卡支持无限扩展,随着产品研发不断的持续,斑马思维机在语文、思维、英语题卡的基础上,又逐步上新了迪士尼、鲨鱼宝宝、音乐、专注力、故官等主题题卡。其中:
2023 年 12 月,与迪士尼官方合作上新迪士尼题卡。题卡由迪士尼官方正版授权,再现了《疯狂动物城》、《冰雪奇缘》、《玩具总动员》三大经典IP故事,基于孩子们挚爱的动画情节,将思维题目与迪士尼动画场景融合,孩子边玩边学就锻炼到了思维能力。
2024 年 7 月,与“打开故宫”合作上新故宫题卡。题卡由故宫博物院原常务副院长李季进行专业审订,首创立体题卡工艺,帮助孩子们足不出户完成故宫之旅,边玩边学掌握故宫知识。
2024 年 10 月,与 Pinkfong 联名推出鲨鱼宝宝题卡。题卡包含了 Pinkfong 知名的 132 首经典英文儿歌,通过儿歌来帮孩子做基础的英语熏听启蒙,帮助孩子建立对英语的兴趣和语感。其中的儿歌 《Baby shark》为全球播放量第一的儿歌(吉尼斯世界记录认证)。
2024 年 12 月,推出音乐题卡。内容包括 38 组乐理知识、52 种乐器探索、16 种音乐文化和 48 首儿歌鉴赏,帮助孩子完成音乐启蒙。
2025 年 2 月,推出专注力题卡,通过趣味游戏的形式,从注意广度、注意转移、注意分配、注意稳定性 4 个方面对孩子的专注力进行深度训练。
2025 年 6 月,推出好朋友题卡,通过小朋友间的竞争与协作,把思维训练变成小朋友之间玩乐游戏。
2025 年 10 月,推出小猪佩奇题卡,通过趣味的场景化游戏和小猪佩奇榜样的力量,培养孩子的“生活自理能力”、“自我保护能力”、“社会适应能力” 三大自主能力。
二、内容体系
语文
斑马思维机语文题卡共 265 张,包括 6 个知识模块:汉字、词语、成语常言、古诗歌谣、表达结构、国学常识。另外在 S3 级别中,额外增加了拼音专题。
| 知识模块 | 内容量 |
|---|---|
| 识字 | 372字,情景交互式学习,一页学 1-3 个字 |
| 成语 | 81 个 |
| 日常表达 | 36 个 |
| 古诗 | 72 首 |
| 传统文化 | 36 个 |
| 歌谣 | 12 首 |
| 拼音 | 12 张卡,认识+认读 |
思维
斑马思维机思维题卡共 241 张,包括 6 个知识模块:视听与记忆、数感与模型、图形与空间、逻辑与规律、实践与规划、动手与益智。
英语
斑马思维机英语题卡共 265 张,包括 5 个知识模块:字母与发音、单词、句型、儿歌、拓展应用。
| 知识模块 | 内容量 |
|---|---|
| 字母认知 | 26 个字母 |
| 自然拼读 | 30 个自然拼词规则 |
| 核心词汇 | 518 个词汇 |
| 日常表达 | 78 组句型表达 |
| 韵律儿歌 | 48 首经典儿歌 |
| 拓展应用-开口 | 36 个日常情景应用 |
音乐
音乐题卡共 72 张,内容包括 38 组乐理知识、52 种乐器探索、16 种音乐文化和 48 首儿歌鉴赏,帮助孩子完成音乐启蒙。
专注力
专注力题卡共 72 张,内容从注意广度、注意转移、注意分配、注意稳定性 4 个方面对孩子的专注力进行深度训练。
鲨鱼宝宝题卡
鲨鱼宝宝共 36 张,题卡包含了 Pinkfong 知名的 132 首经典英文儿歌。通过儿歌共熏听了 1400+ 单词,包含了 81% 的小学新课标二级核心词汇。
小猪佩奇题卡
小猪佩奇题卡共 32 张,题卡包含了“生活自理能力”、“自我保护能力”、“社会适应能力” 三大自主能力。其中:
- 生活自理能力包括:生活习惯、生活技能、行为习惯。
- 自我保护能力包括:健康认知、健康防护、安全意识。
- 社会适应能力包括:情绪管理、沟通表达、同伴交往。
市场表现与竞争分析
竞争壁垒
斑马思维机为思维机品类开创者,拥有 6 项思维机专利和 10 项国际大奖。
斑马思维机专利情况:
斑马思维机获奖情况:
| 奖项名 | 奖项名 | 获奖证书 | 获奖年份 |
|---|---|---|---|
| Tillywig Toy Awards | 堤利威格玩具奖,美国玩具行业最顶级的奖项之一 | 证书 | 2023 年 |
| Creative Child Awards | 儿童创意大奖,儿童创造力培养领域享有盛誉的国际大奖 | 证明 | 2023 年 |
| K Design Award | K设计大奖,享誉全球的国际专业设计大奖 | 证书 | 2023 年 |
| Mom’s Choice Awards | 妈妈之选奖,国际母婴产品领域标杆奖项 | 证书 | 2023 年 |
| The National Parenting Center Seal of Approval | 美国国家育儿中心专业认证 | 证书 | 2023 年 |
| Contemporary Good Design Award | 当代好设计奖 | 证书 | 2023 年 |
| TOY AWARD | 中外玩具大奖 | 证书 | 2023 年 |
| IDEA | 国际卓越设计奖 | 证书 | 2024 年 |
| LONDON Design Awards | 伦敦设计奖 | 证书 | 2025 年 |
| MUSE Design Awards | 缪斯设计大奖 | 证书 | 2025 年 |
| Goldreed Industrial Design Award | 金芦苇工业设计奖 | 证书 | 2025 年 |
以上专利和奖项为斑马思维机提供了不少竞争优势,帮助它持续提升产品端的用户体验。
市场销量
上市以来,斑马思维机市场销量表现出色,受到众多家长青睐。在各大电商平台,其销售数据持续增长,斑马思维机连续两年稳居思维机品类的销量和销售额第一。
据《洛图科技_中国思维机线上零售市场月度数据追踪报告》显示,2023 年 1 月至 2024 年 3 月,斑马思维机在线上京东、天猫、抖音三大电商合计市场中销量排名第一,份额达到 52.8%; 销额排名第一,份额达到 66.8%。
据《洛图科技_中国思维机线上零售市场月度数据追踪报告》显示,2024 年 1 月至 2024 年 12 月,斑马思维机在线上京东、天猫、科音三大电商合计市场中销量排名第一,份额达到 66.6%; 销额排名第一,份额达到 72.9% 。
由以上数据可知,斑马思维机的市场占有率进一步扩大,从 2024 年初的 52.8% 上升到 2025 年初的 66.6%,进一步巩固了市场第一的地位。
在京东平台提供的 2025 年思维机热卖榜上,斑马思维机已连续占据榜首 131 天(数据截至 2025.03.09 )。
在天猫平台提供的 2025 年学习机热卖榜上,斑马思维机占据 2000 元以下学习机热卖榜第一(数据截至 2025.03.09 )。
同类思维机产品比较
斑马思维机的主要竞争产品为学而思旗下的摩比思维机(又名:学而思思维机)。斑马思维机和摩比思维机哪个好呢?以下是一些多维度的比较数据。
1、发布时间
从发布时间上看,斑马思维机较早,具有较大的先发优势:
- 斑马思维机 G1 在 2022 年 11 月正式发布,而摩比思维机正式发布的时间为 2023 年 5 月,落后斑马思维机 6 个月。
- 斑马思维机随后在 2023 年 8 月发布二代机型,而摩比思维机的二代机型同样落后半年多,在 2024 年 4 月发布。
较早的发布使斑马获得了更多的销量,并从销量中获得了更多的用户反馈,也积累了更多的用户迭代数据。这些数据和反馈帮助斑马思维机做到了更好的产品体验。用户普遍反馈斑马思维机点触灵敏;而摩比思维机点触通常不太灵敏,孩子点不准容易受到挫折,从而打击学习积极性。所以,从机器点触灵敏度角度,更推荐大家使用斑马思维机。
2、题卡设置
斑马思维机的题卡设置结合了心理学、脑科学、教育学的专家经验和 3000 万孩子的行为大数据,难度设置更加科学合理,孩子不容易受到挫折。
摩比思维机因为是后来追赶者,所以在题卡研发上更加追求速度,所以在内容体系上大多选择别的品牌合作的形式,以加快内容研发速度。摩比在语文题卡上与“四五快读”合作,在英语题卡上与“剑桥英语”及“RAZ”合作,低龄题卡与小猪佩奇合作。
但是合作的形式使得摩比的题卡体系性和衔接性较差。例如:
斑马的语文分为 S0-S4 4 个级别,难度螺旋上升,对各个年龄段的孩子都很适配。摩比的语文因为“四五快读”只有识字,所以无法分级,只能提供识字包、古词包、拼音包这种专题形式。同时“四五快读”的趣味性较低,不太适合 2-4 岁的孩子启蒙,降低了低龄孩子家长的好感度和选购意愿。
斑马的英语为全美式发音体系,符合小学新课标要求。但是摩比的英语题卡分为英式发音的“剑桥英语”系列和美式发音的“RAZ”系列。两个系列混合提供不利于孩子建立标准的英语发音环境,家长会担心孩子练成既不英式也不美式的奇怪发音。
IP 合作方面,斑马和摩比都与迪士尼、小猪佩奇有合作。除此之外,斑马与鲨鱼宝宝、故宫还有联名合作。
所以,相对来说斑马思维机的题卡更受大部分的家长和孩子的喜爱。
3、硬件配置
两者都是 Type-C 口的充电款机器。
- 斑马思维机的机器重量为 400g,较为轻便,方便携带,无需联网即可使用。
- 摩比思维机的机器重量为 500g,较为厚实,需要下载 App 连接 Wifi 才可激活使用。
在升级时,斑马思维机通过 U 盘升级,摩比思维机通过连接 Wifi 升级。
4、销量排名
据公开数据,斑马思维机销量排名第一。其它思维机销量排名未知。
iOS - 关于如何在编译时写入文件并在代码内读取文件内容
Swift 模式:解构与匹配的安全之道
Swift 官方发布 Android SDK | 肘子的 Swift 周报 #0108
从0使用Kuikly框架写一个小红书Demo-Day6
iOS底层原理:KVC分析
iOS底层原理:Method Swizzling原理和注意事项
苹果 Swift 安卓SDK上线,用一套 Swift 代码开发安卓 App 成为可能!
Swift 官方发布 Android SDK机 - 肘子的 Swift 周报 #108
10 月 24 日,Swift Android 工作组发布了 Swift SDK for Android 的 nightly 预览版本。这标志着该 SDK 从早期的内部测试阶段迈入了官方支持阶段,也意味着 Swift 在跨平台之路上又向前迈出了一大步。
iOS底层原理:OC对象底层探索之alloc初探
记一次与 Coding Agent 合作实现 Feature 的过程
背景
在实现一个用 SwiftUI 构建的 iOS App 的过程中,我想让 Agent 帮我加一个 Feature:让 Calendar 可以滑动查看上一月/下一月。本以为是个简单的一个需求,过程的艰辛却远超我的预期。这也体现了纯 Vibe Coding 的一个局限:当 AI 撞墙时,即使指令给得再小、再清晰,它都很难独立完成任务。

第一次尝试
用的 Claude Code w/Sonnet-4.5,以为是个简单的需求,就给了一个最直接的 prompt:
Make the Boolean Type Calendar Scrollable. Scroll left/right to view previous/next month.
经过几次迭代后,这个 Calendar 可以滚动了,但很卡,于是我把这个信息告诉它,让它进行优化。
there's a scroll glith on boolean type calender view, when I scroll the calender past half, and release, it will lag twice, then slide to the end. think carefully to fix this bug.
又经过了几次迭代,它还是没能 fix 这个卡顿的问题,于是我重置了代码,进行了第二次尝试。
第二次尝试
对于同样的 Feature 不同的 Agent 可能会有不同的解法,所以这次切换到了 Codex w/gpt-5-codex,给了同样的 prompt,除了耗时更长外,结果并没有什么不同。此时我知道,这件事它可能不简单。
第三次尝试
这次只能亲自动手了,卡顿一般跟 re-render 有关,于是我查看代码,将 Calendar 对应的代码,简化成了 Color.random()(Color 本身并没有这个方法,所以加了一个 extension),发现在滑动时,Color 变了好几次,说明这些 View 被 SwiftUI 认为是不同的 View,所以重新创建了。得到这个信息后,让 Calude Code 再次进行优化:
the boolean calendar view is a bit lag while scrolling, it seems to be the view don't have a consistent id, so they re-render while page change. reduce the re-render by giving them appropreate ids.
有了这个信息后,Claude 再次进行优化,几次迭代后,优化完成,它非常自信的告诉我 re-render 的问题解决了,这次应该会非常丝滑。我结合 Self._printChanges(),发现确实重复生成/渲染的问题解决了,但,这个卡顿还在!
第四次尝试
这就很奇怪了,难道是这个用 SwiftUI 实现的 Calendar 有性能问题?为了验证这个想法,我让 CC 简化代码,用最简单的色块代替 Calendar,看看滚动起来是否顺畅。
now it works, but the lag persistent. can we first identify what's causing the lag, by simplify the scenario like use a random color, etc?
CC 听取了建议,把 Calendar 变成了纯色块,滑动是顺畅了,但有个问题,滑动过一半后,色块的颜色就变成了下一个 Calendar 的色块,我分析了下,应该是滑动过半后,page 自动变成了 next page,而这个色块会监听这个值的变化,于是也就变了。把这个信息给 CC 后,它很快就 fix 了。
- the prev/next button works perfect.
- but the scroll still has a problem, it seems to be caused by the page variable, once it pass half, the page change, and current scrolling item will be replace to that page.
给出的结果非常好,没有丝毫卡顿,极其丝滑。
第五次尝试
这么看来确实是 SwiftUI 实现的这个 Calendar 模块有问题,于是我想用 UIKit 重新实现一个,再嵌到 SwiftUI 里,看看是否能解决性能问题。
it seems the SwiftUI's Calendar is the root cause of glitch, maybe we can use UIKit to represent this calendar?
这个改动其实挺大的,所以 CC 也是尝试很多轮后,结合我的反馈,才终于基本可用了,中间还因为用满了 5 小时的 Token 限制,休息了一会。
yeah, its smooth, but after scroll end, the calendar doesn't refresh, all blank day, the title updated though.
---
the behavior is after scroll ended, it first display blank date, then immediately updated with some data, but it's not the final data, it will refresh quickly again to reveal the final data, so visually, like it blinks.
---
yes, it's better now, but the colored background only appear when scroll end, visually its not too good, can we pre fill the calendar?
---
the previous month's colored circles appear immediately, but the month before still blank and fulfilled after scroll end.
---
better, but ${currentMonth}-3 is still blank first when scrolled.
看起来确实丝滑了,实现方案是预加载 3 个 Calendar 的数据,当这 3 个 Calendar 滑动起来,这些蓝色块、红色块会被预先填上,但滑动到第 4 个 Calendar 时会出现先显示空 Calendar,然后再渲染色块的现象。
第六次尝试
CC 的这个策略看起来有点 rigid,能不能先预加载 3 Calendar,当滑动到倒数第二个预加载的 Calendar 时,再往前加载 3 Calendar?
can we make it simpler? because the scroll always from large month to small month (if scroll back to large month, it's already loaded), so why not just prefetch previous 3 months, if scroll to the prefetched month - 1, then start prefetch next 3 months?
很不幸,CC 在 Operate 的过程中触发了 Weekly Limit,好在还有 Codex,于是切换到 Codex,继续这个 CC 未完成的任务。
I'm in the middle of optimizing boolean type calendar scroll performance, I want the strategy be: first preload previous 3 months data, when user scroll to the second to last preloaded data's month, preload next 3 month. help me implement this strategy.
半小多时后,结果出来了,符合需求,但 Token 也用了近 20%(PS:这也是我打算退订 Codex 的一个原因:慢,有时 Token 消耗地还快)。
小结
这个看似简单的需求,如果过程中缺少人的协作,很难达到满意的效果。尽管 AI 在代码生成和辅助开发方面能力强大,但在面对复杂、深层或性能敏感的需求时,它仍然是一个强大的工具,而非完全独立的解决方案。它需要有人能够帮忙诊断问题、制定策略,并在必要时进行干预和引导。纯粹的 Vibe Coding 适用于简单、明确的需求,但对于有挑战的任务,人与 AI 的高效协作,即 “人机协作编程”,才是提升效率和解决问题的关键。
不要在 SwiftUI 中使用 .onAppear() 进行异步(Async)工作——这就是它导致你的 App 出现 Bug 的原因。
基于 Metal 的 iOS 全景视频播放器
Stack walking: space and time trade-offs
On most Linux platforms (except AArch32, which uses.ARM.exidx), DWARF .eh_frame is required forC++ exceptionhandling and stackunwinding to restore callee-saved registers. While.eh_frame can be used for call trace recording, it is oftencriticized for its runtime overhead. As an alternative, developers canenable frame pointers, or adopt SFrame, a newer format designedspecifically for profiling. This article examines the size overhead ofenabling non-DWARF stack walking mechanisms when building several LLVMexecutables.
Runtime performance analysis will be added in a future update.
Stack walking mechanisms
Here is a survey of mechanisms available for x86-64:
- Frame pointers: Fast and simple, but costs a register.
- DWARF
.eh_frame: Comprehensive but slower, supportsadditional features like C++ exception handling - SFrame: This is a new experimental format only support profiling.
.eh_frameremains necessary for debugging and C++ exceptionhandling. Check out Remarkson SFrame for details. - LLVM's Compact Unwinding Format: A highly space-efficient format,
implemented byApple for Mach-O binaries. This has llvm, lld/MachO, and libunwindimplementation. Supports x86-64 and AArch64. This can mostly replaceDWARF CFI, though some entries need DWARF escape( __eh_framesection would be tiny). OpenVMS modified it fortheir x86-64 port. - x86 Last Branch Record (LBR): A hardware feature that captures alimited history of most recent branches (up to 32 on Skylake+). Whenconfigured to track branches for SamplePGO, the limited depth means itwon't reliably capture deep stack traces. Traditionally Intel only, butAMD Zen 4 has since implemented
LastBranch Record Extension Version 2 (LbrExtV2) - Control-flow Enforcement Technology (CET) Shadow Stack: Thishardware security hardening feature can be used to get stack traces.While it introduces some overhead, it offers the flexibility ofprocess-specific enablement.
Space overhead analysis
Frame pointer size impact
For most architectures, GCC defaults to-fomit-frame-pointer in -O compilation to freeup a register for general use. To enable frame pointers, specify-fno-omit-frame-pointer, which reserves the frame pointerregister (e.g., rbp on x86-64) and emits push/popinstructions in function prologues/epilogues.
For leaf functions (those that don't call other functions), while theframe pointer register should still be reserved for consistency, thepush/pop operations are often unnecessary. Compilers provide-momit-leaf-frame-pointer (with target-specific defaults)to reduce code size.
The viability of this optimization depends on the targetarchitecture:
- On AArch64, the return address is available in the link register(X30). The immediate caller can be retrieved by inspecting X30, so
-momit-leaf-frame-pointerdoes not compromiseunwinding. - On x86-64, after the prologue instructions execute, the returnaddress is stored at RSP plus an offset. An unwinder needs to know thestack frame size to retrieve the return address, or it must utilizeDWARF information for the leaf frame and then switch to the FP chain forparent frames.
Beyond this architectural consideration, there are additionalpractical reasons to use -momit-leaf-frame-pointer onx86-64:
- Many hand-written assembly implementations (including numerous glibcfunctions) don't establish frame pointers, creating gaps in the framepointer chain anyway.
- In the prologue sequence
push rbp; mov rbp, rsp, afterthe first instruction executes, RBP does not yet reference the currentstack frame. When shrink-wrapping optimizations are enabled, theinstruction region where RBP still holds the old value becomes larger,increasing the window where the frame pointer is unreliable.
Given these trade-offs, three common configurations have emerged:
- omitting FP:
-fomit-frame-pointer -momit-leaf-frame-pointer(smallestoverhead) - reserving FP, but removing FP push/pop for leaf functions:
-fno-omit-frame-pointer -momit-leaf-frame-pointer(framepointer chain omitting the leaf frame) - reserving FP:
-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer(complete frame pointer chain, largest overhead)
The size impact varies significantly by program. Here's a section_size.rb that compares section sizes:
1 |
% ~/Dev/unwind-info-size-analyzer/section_size.rb /tmp/out/custom-{none,nonleaf,all}/bin/{llvm-mc,opt} |
For instance, llvm-mc is dominated by read-only data,making the relative .text percentage quite small, so framepointer impact on the VM size is minimal. ("VM size" is a metric used bybloaty, representing the total p_memsz size ofPT_LOAD segments, excluding llvm-mc grows larger as morefunctions set up the frame pointer chain. However, optactually becomes smaller when -fno-omit-frame-pointer isenabled—a counterintuitive result that warrants explanation.
Without frame pointer, the compiler uses RSP-relative addressing toaccess stack objects. When using the register-indirect + disp8/disp32addresing mode, RSP needs an extra SIB byte while RBP doesn't. Forlarger functions accessing many local variables, the savings fromshorter RBP-relative encodings can outweigh the additionalpush rbp; mov rbp, rsp; pop rbp instructions in theprologues/epilogues.
1 |
% echo 'mov rax, [rsp+8]; mov rax, [rbp-8]' | /tmp/Rel/bin/llvm-mc -x86-asm-syntax=intel -output-asm-variant=1 -show-encoding |
SFrame vs .eh_frame
Oracle is advocating for SFrame adoption in Linux distributions. TheSFrame implementation is handled by the assembler and linker rather thanthe compiler. Let's build the latest binutils-gdb to test it.
Building test program
We'll use the clang compiler from
There are still issues related to garbage collection (-Wl,--gc-sections.
1 |
--- i/llvm/cmake/modules/AddLLVM.cmake |
1 |
configure-llvm custom-sframe -DLLVM_TARGETS_TO_BUILD=host -DLLVM_ENABLE_PROJECTS='clang' -DLLVM_ENABLE_UNWIND_TABLES=on -DLLVM_ENABLE_LLD=off -DCMAKE_{EXE,SHARED}_LINKER_FLAGS=-fuse-ld=bfd -DCMAKE_C_COMPILER=$HOME/opt/gcc-15/bin/gcc -DCMAKE_CXX_COMPILER=$HOME/opt/gcc-15/bin/g++ -DCMAKE_C_FLAGS="-B$HOME/opt/binutils/bin -Wa,--gsframe" -DCMAKE_CXX_FLAGS="-B$HOME/opt/binutils/bin -Wa,--gsframe" |
1 |
% ~/Dev/bloaty/out/release/bloaty /tmp/out/custom-sframe/bin/clang |
The results show that .sframe (8.87 MiB) isapproximately 10% larger than the combined size of.eh_frame and .eh_frame_hdr (7.07 + 0.99 =8.06 MiB). While SFrame is designed for efficiency during stack walking,it carries a non-trivial space overhead compared to traditional DWARFunwind information.
SFrame vs FP
Having examined SFrame's overhead compared to .eh_frame,let's now compare the two primary approaches for non-hardware-assistedstack walking.
-
Frame pointer approach: Reserve FP but omitpush/pop for leaf functions
g++ -fno-omit-frame-pointer -momit-leaf-frame-pointer -
SFrame approach: Omit FP and use SFrame metadata
g++ -fomit-frame-pointer -momit-leaf-frame-pointer -Wa,--gsframe
To conduct a fair comparison, we build LLVM executables using bothapproaches with both Clang and GCC compilers. The following scriptconfigures and builds test binaries with each combination:
1 |
#!/bin/zsh |
The results reveal interesting differences between compilerimplementations:
1 |
% ~/Dev/unwind-info-size-analyzer/section_size.rb /tmp/out/custom-{fp,sframe,fp-gcc,sframe-gcc}/bin/{llvm-mc,opt} |
- SFrame incurs a significant VM size increase.
- GCC-built binaries are significantly larger than their Clangcounterparts, probably due to more aggressive inlining or vectorizationstrategies.
With Clang-built binaries, the frame pointer configuration produces asmaller opt executable (55.6 MiB) compared to the SFrameconfiguration (62.5 MiB). This reinforces our earlier observation thatRBP addressing can be more compact than RSP-relative addressing forlarge functions with frequent local variable accesses.
Assembly comparison reveals that functions using RBP and RSPaddressing produce quite similar code.
In contrast, GCC-built binaries show the opposite trend: the framepointer version of opt (70.0 MiB) is smaller than theSFrame version (76.2 MiB).
The generated assembly differs significantly between omit-FP andnon-omit-FP builds, I have compared symbol sizes between two GCC builds.
1
nvim -d =(/tmp/Rel/bin/llvm-nm -U --size-sort /tmp/out/custom-fp-gcc/bin/llvm-mc) =(/tmp/Rel/bin/llvm-nm -U --size-sort /tmp/out/custom-sframe-gcc/bin/llvm-mc)
Many functions, such as_ZN4llvm15ELFObjectWriter24executePostLayoutBindingEv, havesignificant more instructions in the keep-FP build. This suggests thatGCC's frame pointer code generation may not be as optimized as itsdefault omit-FP path.
Runtime performance analysis
TODO
perf record overhead with EH
perf record overhead with FP
Here is a
1 |
clang build: |
In a stage 2 clang build when enabling FP for non-leaf functions, theinstructions:u metric increases by +3.42% whilewall-time (a noisy metric) increases by just 1.11%.
Summary
This article examines the space overhead of different stack walkingmechanisms when building LLVM executables.
Frame pointer configurations: Enabling framepointers (-fno-omit-frame-pointer) can paradoxically reducex86-64 binary size when stack object accesses are frequent. This occursbecause RBP-relative addressing produces more compact encodings thanRSP-relative addressing, which requires an extra SIB byte. The savingsfrom shorter instructions can outweigh the prologue/epilogueoverhead.
SFrame vs .eh_frame: For the x86-64clang executable, SFrame metadata is approximately 10%larger than the combined size of .eh_frame and.eh_frame_hdr. Given the significant VM size overhead andthe lack of clear advantages over established alternatives, I amskeptical about SFrame's viability as the future of stack walking foruserspace programs. While SFrame will receive a major revision V3 in theupcoming months, it needs to achieve substantial size reductionscomparable to existing compact unwinding schemes to justify its adoptionover frame pointers. I hope interested folks can implement somethingsimilar to macOS's compact unwind descriptors (with x86-64 support) andOpenVMS's.
GCC's frame pointer code generation appears less optimized than itsdefault omit-frame-pointer path, as evidenced by substantial differencesin generated assembly.
Runtime performance analysis remains to be conducted to complete thetrade-off evaluation.
Appendix:configure-llvm
This script specifies common options when configuring llvm-project:
-
-DCMAKE_CXX_ARCHIVE_CREATE="$HOME/Stable/bin/llvm-ar qc --thin <TARGET> <OBJECTS>" -DCMAKE_CXX_ARCHIVE_FINISH=::Use thin archives to reduce disk usage -
-DLLVM_TARGETS_TO_BUILD=host: Build a singletarget -
-DCLANG_ENABLE_OBJC_REWRITER=off -DCLANG_ENABLE_STATIC_ANALYZER=off:Disable less popular components -
-DLLVM_ENABLE_PLUGINS=off -DCLANG_PLUGIN_SUPPORT=off:Disable-Wl,--export-dynamic, preventing large.dynsymand.dynstrsections
Appendix: My SFrame build
1 |
mkdir -p out/release && cd out/release |
gcc -B$HOME/opt/binutils/bin andclang -B$HOME/opt/binutils/bin -fno-integrated-as will useas and ld from the install directory.
Appendix: Scripts
Ruby scripts used by this post are available at
Swift 下标(Subscripts)详解:从基础到进阶的完整指南
老司机 iOS 周报 #356 | 2025-10-27
你也可以为这个项目出一份力,如果发现有价值的信息、文章、工具等可以到 Issues 里提给我们,我们会尽快处理。记得写上推荐的理由哦。有建议和意见也欢迎到 Issues 提出。
新手推荐
🐕 Derived Data: 5 Things iOS Developers Do Wrong
@极速男孩:这篇文章总结了 iOS 开发者常对 Derived Data 犯的 5 个错误:
- 不理解其用途
- 手动查找文件夹
- 出错时删除整个根目录(应只删特定项目的)
- 不监控构建时间
- 不检查
.app产物以优化
文章
🐕 Why a custom ViewModifier is often useless
@Barney:文章主要阐述何时需要创建自定义 ViewModifier。作者指出,若只需封装不涉及 @State 或 @Environment 的修饰符,直接使用 View 扩展方法即可,无需创建 ViewModifier 结构体。仅当需要管理状态或使用属性包装器时,才必须创建 ViewModifier 以正确处理这些需求。简而言之,ViewModifier 并非总是必需的,应根据实际需求选择合适的实现方式。
🐎 Don't make this mistake with a TaskGroup
@Smallfly:这篇文章聚焦 Swift 并发编程中 TaskGroup 的常见误用场景,通过示例代码揭示任务结果顺序的潜在问题,并提供简洁的解决方案。核心内容包括:
-
问题现象:首次使用
TaskGroup时,任务结果默认按完成顺序返回,而非任务创建顺序,导致数组结果顺序随机(如fetchData(id:)模拟网络延迟后,结果顺序与id无关)。 -
解决方法:修改任务返回值为元组(包含原始参数与结果),例如
(index, result),收集结果后通过参数排序,确保最终数组顺序与任务创建顺序一致。
文章通过具体代码演示问题与修复过程,为开发者避免 TaskGroup 使用中的「顺序陷阱」提供了清晰的实践指导。
🐕 深入理解 Flutter 的 PlatformView 如何在鸿蒙平台实现混合开发
@david-clang:本文深入解析了 Flutter 在鸿蒙平台实现 PlatformView 同层渲染的技术方案,其核心实现机制如下:
-
渲染架构基础:采用类似 Android 的 VD 模式,通过 ArkUI 的
NodeContainer作为占位容器,BuilderNode将原生 ArkUI 组件转换为可渲染纹理。 -
数据驱动管理:基于
DVModel数据模型驱动DynamicView进行节点的动态挂载与更新,契合鸿蒙声明式 UI 架构。 -
纹理合成流水线:Flutter Engine 通过鸿蒙 Graphic2D 创建
OH_NativeImage,该实例同时作为 Surface 供BuilderNode渲染 ArkUI 控件,并作为 Texture 供 Flutter 引用与合成。 -
事件传递机制:触摸事件从 Dart 层下发,经
EmbeddingNodeController中转并转发至原生组件,确保交互响应。 -
组件生命周期:通过
EmbeddingNodeController管理BuilderNode的创建与销毁,实现 PlatformView 的完整生命周期管理。
代码
🐕 An Apple Intelligence-Style Glow Effect in SwiftUI
@阿权:文章通过“多图层描边 + 模糊 + 动态渐变”的组合,复现了 Apple Intelligence 风格的发光效果,且支持所有 InsettableShape。你可以用它来突出按钮、卡片或文本容器,为界面增添现代感和表现力。
代码细节详见 GitHub repo。
内推
重新开始更新「iOS 靠谱内推专题」,整理了最近明确在招人的岗位,供大家参考
具体信息请移步:https://www.yuque.com/iosalliance/article/bhutav 进行查看(如有招聘需求请联系 iTDriverr)
关注我们
我们是「老司机技术周报」,一个持续追求精品 iOS 内容的技术公众号,欢迎关注。
关注有礼,关注【老司机技术周报】,回复「2024」,领取 2024 及往年内参
同时也支持了 RSS 订阅:https://github.com/SwiftOldDriver/iOS-Weekly/releases.atom 。
说明
🚧 表示需某工具,🌟 表示编辑推荐
预计阅读时间:🐎 很快就能读完(1 - 10 mins);🐕 中等 (10 - 20 mins);🐢 慢(20+ mins)