# Cursor React 内存泄漏排查：反复预览图片后释放 Object URL 和监听器

React原生Effect对照十张图片，缺清理残留10个URL/监听器，完整清理关闭后两者为0；不是堆内存测量。

## 环境

- Node.js 24+；进入 reference 后 npm install。依赖为锁定的直接版本，首次安装需要网络。
- npm run build 后再启动HTTP服务。编译bundle与WASM运行时不随包分发，build.mjs从本地npm依赖准备。

## 启动

~~~sh
cd reference
npm install
npm run build
python3 -m http.server 8787
~~~

## 七步操作

1. 准备十张图片

输入是十张原创几何PNG，使用浏览器File对象预览。每次切换图片都生成Object URL，并登记一个resize监听器，便于观察生命周期。

2. 观察Effect资源

在React useEffect中创建预览URL与监听器。创建动作和清理动作必须属于同一次Effect，不能用新回调去remove旧监听器。

3. 复现缺清理

先选择故意缺清理版本，连续切换十张后关闭预览。真实活动URL和监听器各留下10个，说明组件消失并不等于外部资源自动释放。

4. 补齐卸载清理

完整版本的Effect返回cleanup，执行URL.revokeObjectURL并移除同一个监听器。新图片切换前以及组件卸载时都会触发这份清理。

5. 切换关闭预览

重新加载页面清空故意泄漏样例，再切到完整版本并重复十次。观察预览期间只有当前资源，关闭后不残留之前图片的URL。

6. 核对资源归零

关闭预览后实际登记的URL数与监听器数都归零。保留缺陷与修复两份对照，别用“页面看起来没变慢”代替生命周期检查。

7. 区分计数与内存

这些数只审计本题显式跟踪的两类资源，不是堆内存、GPU或垃圾回收测量。下载React源码可继续扩充快速切换、空输入与解码失败场景，Cursor账号未运行。

## 目录身份

- starter：待完成的任务接口与原创输入，TODO不是已完成实现。
- reference：作者原生完成参考和实际产物。records.json/browser-result.json为本地实测记录，不是AI助手回复。
- TASK.md：可交给相应AI助手的原始任务合同。该助手账号生成会话未运行。

## 依赖与许可

原创教学代码以MIT许可提供。第三方项目、模型及浏览器遵循其自身许可。第三方依赖由本地安装获取，不包含node_modules、模型权重、WASM运行时、数据库、缓存或凭据。

## 官方依据

- https://react.dev/reference/react/useEffect
