根本原因是will-change: transform为每个元素强建独立GPU合成层,显存按Width×Height×4×DPR²暴增;DPR=3时单个375×240px卡片占3.24MB,80个即超260MB,远超移动端100–200MB GPU内存上限,触发Jetsam强制杀进程。

will-change 触发 GPU 显存爆炸,直接撞上 Jetsam 红线
根本原因不是代码写错,而是 will-change: transform 在滑动中为每个元素强建独立合成层,显存占用按 Width × Height × 4 × DPR² 暴增。一台 DPR=3 的安卓机上,一个 375×240px 卡片就要吃掉约 3.24MB 显存;瀑布流渲染 80 个同加该声明的卡片,仅纹理就占 260MB+。移动端 GPU 共享内存通常仅 100–200MB,瞬间 OOM 后系统内核强制杀进程——表现为黑屏、闪退、Safari 弹出“此网页出现问题”。
旧版 WebView 图层不回收,内存持续泄漏
Android 4.4–6.0 的 WebView 存在合成器缺陷:will-change 设定后,即使动画结束、样式清空,GPU 图层也不会释放。Layers 面板里图层数只涨不跌,几秒内堆满 32MB 默认上限,最终黑屏卡死。这不是偶发 Bug,是真实可复现的生命周期失控。
- 真机验证方式:打开 Chrome DevTools → Rendering → 勾选 «Layer borders»,滑动后观察橙色边框是否持续累积不消失
- 绝对不要在 CSS 文件里写
.item { will-change: transform; }—— 这等于给每个 item 发一张永不注销的 GPU 内存卡 - 旧引擎对
backface-visibility: hidden和will-change叠加极度敏感,可能直接让 absolute 子元素不可见
低版本 Chrome 强制创建层叠上下文,z-index 失效
Chrome 60–79 中,will-change: transform 不仅升层,还会无条件创建新层叠上下文(Stacking Context),导致子元素的 z-index 只在内部生效,完全无法和外部同级元素比大小。典型现象是弹窗按钮被导航栏盖住,DevTools Layout 标签页显示 “Stacking Context: Yes”,但你改再多 z-index 都没用。
- 清除方法只能是显式设
will-change: initial或彻底删掉该声明,will-change: auto在老版本里无效 - 更隐蔽的问题:iOS 15.4 及更早 Safari 中,只要
position: sticky元素的任意祖先设了will-change: transform,sticky 就会退化成static,定位逻辑被截断
动态设置时机错位,资源白占还拖垮主线程
很多崩溃源于“提前加、忘记清”。比如在 touchstart 就加 will-change,但用户只是轻点而非长滑;或监听 transitionend 失败(iOS Safari 常不触发),导致图层常驻。中低端安卓机图层超 5~8 个后,纹理上传就开始阻塞,帧率断崖下跌,合成器压力过大反而触发底层保护机制崩溃。
立即学习“前端免费学习笔记(深入)”;
- 正确时机:仅在
touchmove开始驱动 transform 的第一帧设element.style.willChange = 'transform' - 清除必须双保险:
animationend回调 +requestAnimationFrame嵌套两层,确保绘制完成后再清,例如:requestAnimationFrame(() => { requestAnimationFrame(() => { el.style.willChange = 'auto'; }); }); - 永远别用
scroll事件触发 set/remove —— 节流延迟会让状态堆积,图层越积越多
will-change 本身,而是它把 GPU 资源预约权交给了开发者,而多数人既没监控 Layers,也没实测真机内存曲线,只凭“看起来顺”就上线。一旦漏掉清理、写错作用域、或低估 DPR 影响,崩溃就是分秒之间的事。


















