game-assets-memory
Skill7 starsChanged 5 months agoMITView on GitHub
管理游戏资源与内存时使用。加载/卸载、图集、包体、泄漏防治。
In this repository47 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- api-designSkill
- chinese-commitSkill
- ci-cd-pipelineSkill
- cocos2dx-luaSkill
- cocos-creator-adaptationSkill
- cocos-creator-bundleSkill
- cocos-creator-drawcallSkill
- cocos-creator-hotupdateSkill
- cocos-creatorSkill
- cocos-creator-tween-animSkill
- cocos-creator-ui-listSkill
- code-review-selfSkill
- concurrency-safetySkill
- core-disciplineSkill
- database-safetySkill
- docker-best-practicesSkill
- domestic-stackSkill
- error-handlingSkill
- frontend-best-practicesSkill
- game-mathSkill
- game-netcodeSkill
- game-performanceSkill
- gameplay-architectureSkill
- godot-gdscriptSkill
- go-idiomsSkill
- input-validationSkill
- integration-testingSkill
- large-repo-refactorSkill
- legacy-safe-editSkill
- naming-thingsSkill
- node-best-practicesSkill
- performance-profilingSkill
- pr-descriptionSkill
- python-idiomsSkill
- requirement-deliverySkill
- rust-safetySkill
- secrets-handlingSkill
- security-reviewSkill
- shell-scripting-safeSkill
- systematic-debuggingSkill
- test-data-managementSkill
- test-drivenSkill
- unity-csharpSkill
- unreal-cppSkill
- writing-docsSkill
The file
Files
资源与内存
何时用
- 新增资源加载逻辑(模型、纹理、音效、配置表)之前。
- 发现内存持续增长、场景切换后内存不降、或 Profiler 显示某类资源异常堆积时。
- 接入新的资源管理系统(Addressables、AssetBundle、自研热更)前做方案评审时。
- 出现「卸载了但内存没降」「切场景崩溃」「包体超预算」等问题排查时。
核心规则
1. 大资源必须异步加载
规则: 纹理、音频、场景、模型等大资源一律走异步接口加载,绝不在主线程同步读取;加载期间必须有合适的 loading 表现,加载完成回调后再使用资源。
为什么: 最常犯的错是原型阶段用同步加载图方便,上线前"有时间再改"——结果积累了几十处同步加载,进游戏时主线程卡顿 2 秒,ANR 投诉爆仓。另一个坑:异步加载发起后立刻用资源(还没加载完),导致空引用崩溃或用到上一次缓存的错误资源。
怎么做:
// Unity 示例
// 反例 — 同步加载阻塞主线程
var tex = Resources.Load<Texture2D>("hero/sword"); // ❌ 主线程阻塞
// 正例 — 异步加载,回调中使用
IEnumerator LoadHeroAsync(string key, Action<GameObject> onLoaded) {
var handle = Addressables.LoadAssetAsync<GameObject>(key);
yield return handle; // ✅ 异步等待
if (handle.Status == AsyncOperationStatus.Succeeded) {
onLoaded(handle.Result); // ✅ 加载完再用
} else {
Debug.LogError($"加载失败: {key}");
}
}- 加载过程中显示 loading 进度条或骨骼屏;加载超时(如 10 秒)要有降级或报错逻辑,不能死等。
- 预加载(Preload)在合适时机(进房间动画期间)提前触发,不要等玩家操作时才开始加载。
2. 引用计数与卸载时机必须明确
规则: 每个资源的生命周期(谁持有、何时释放)必须在接入时明确设计;场景切换时主动释放当前场景独占的资源,不依赖 GC 或引擎的"自动"回收。
为什么: 最典型的泄漏路径:战斗场景加载了 50 个怪物预制体的纹理,战斗结束切回大厅,没有主动 Release,Addressables 的引用计数没归零,纹理全留在内存里。打完十场战斗内存涨到崩溃。反向问题也有:卸载太激进,在某个地方还持有引用时就强制卸载,运行时出现粉色/错误材质。
怎么做:
- 使用 Addressables/AssetBundle 时,每次
LoadAssetAsync对应一次Release,用 RAII 或引用计数封装保证配对。 - 场景切换时有明确的「场景资源卸载」阶段:先通知所有系统释放本场景资源引用,再触发
UnloadUnusedAssets。 - 共享资源(公共 UI 图集、常驻音效)单独管理,不随场景卸载;战斗专属资源随战斗结束卸载。
- 建立资源持有关系图(哪个系统持有哪些资源),在代码注释或文档中维护,避免「不知道谁在引用」的黑盒状态。
3. 图集与压缩格式要选对
规则: UI 精灵和 2D 素材必须打图集减少 Draw Call;纹理压缩格式按平台和内容类型选择(Android 用 ETC2/ASTC,iOS 用 ASTC,PC 用 BC7/DXT5),不能全部用未压缩 RGBA32。
为什么: 没用图集的 UI 场景,100 个图标就是 100 个 Draw Call,低端机直接掉帧。纹理压缩格式用错更隐蔽:开发时在 PC 上用 RGBA32 完全没问题,发布到手机后内存翻 4 倍(一张 1024×1024 的 RGBA32 纹理占 4MB,ASTC 6×6 只占约 0.4MB),低端安卓机直接 OOM。
怎么做:
- UI 按功能模块分图集(主界面、战斗 HUD、商店分别打包),单张图集不超过 2048×2048,避免单图集过大导致无法在低端机加载。
- 纹理导入设置模板化:为 Android/iOS/PC 各建一套 Preset,批量应用,避免手动逐张配置遗漏。
- 带 Alpha 通道的 UI 纹理用 ASTC 4×4(iOS/高端安卓)或 ETC2 RGBA8(中低端安卓);无 Alpha 的背景用 ETC2 RGB8 或 ASTC 6×6。
- 定期用 Memory Profiler / Texture Overview 工具扫一遍纹理列表,找出没被图集收录的散图和格式设置异常的资源。
4. 监听/回调/缓存在销毁时必须清理
规则: 任何在对象初始化时注册的事件监听、委托回调、定时器、或加入全局缓存的引用,必须在对象销毁时对称地反注册/清除,禁止依赖"对象被回收后监听自动失效"的侥幸心理。
为什么: 最隐蔽的内存泄漏:UI 面板注册了全局事件总线的监听(EventBus.on("kill", OnKill)),面板关闭时忘了反注册。面板对象被「销毁」了,但事件总线还持有对它的引用,GC 永远不会回收它。玩家反复开关面板,内存里堆着几十个"已关闭"的面板实例。更严重的是:Dead 对象收到事件后访问已回收的 UI 组件,直接 NullReferenceException 崩溃。
怎么做:
// Unity 示例
public class KillFeedUI : MonoBehaviour {
void OnEnable() {
EventBus.Subscribe("kill", OnKill); // ✅ 启用时注册
}
void OnDisable() {
EventBus.Unsubscribe("kill", OnKill); // ✅ 禁用时对称反注册
}
// 反例 — 只在 Start 注册,没有对应的 OnDestroy 反注册
// void Start() { EventBus.Subscribe("kill", OnKill); } // ❌
}- 静态字典/列表缓存中存放对象引用时,优先使用
WeakReference(弱引用),或在对象销毁时主动从缓存中移除。 - Coroutine/Timer 在对象销毁前必须 Stop/Cancel;异步操作持有的 CancellationToken 在销毁时触发。
5. 内存与包体要设预算,定期用工具检查峰值
规则: 项目立项时为内存和包体设定明确预算(如:手机目标设备内存上限 1.2GB,包体初始安装包不超过 150MB),并在 CI 或版本里程碑节点用自动化工具检查,超预算视为 P1 问题。
为什么: 最常见的失控模式:开发初期没有预算约束,美术资源按"效果最好"的规格产出,等到上线前两周发现手机低端机直接崩溃或包体超出渠道限制,再来全量优化——成本是前期的 10 倍。另一个盲区:开发机内存 16GB,测试机 8GB,发布目标机 3GB,开发全程感觉"没问题",实际目标用户全程 OOM。
怎么做:
- 明确定义目标设备(如:低端 Android 3GB RAM、iOS iPhone 12 作为最低支持型号)并用真机定期测试。
- 在 CI 流水线中加入包体检查脚本,超过阈值自动发告警;Memory Profiler 截图在每个里程碑节点存档对比。
- 为各类资源分配子预算(纹理、音频、代码、Shader 各多少),防止一类资源无限膨胀挤占其他资源。
- 内存峰值出现在战斗中场景最复杂时,专门在该时机做 Profiler 快照,不能只测大厅/菜单场景。
正例 / 反例
反例:忘记 Release,场景切换后内存不降
// 反例 — 加载后没有对应的 Release,切场景时内存全留着
public class BattleManager : MonoBehaviour {
List<AsyncOperationHandle<GameObject>> handles = new();
async void SpawnEnemy(string key) {
var h = Addressables.LoadAssetAsync<GameObject>(key);
await h.Task;
handles.Add(h);
Instantiate(h.Result, spawnPos, Quaternion.identity);
}
void OnDestroy() {
// ❌ 没有 foreach Release,所有纹理/预制体留在内存里
}
}// 正例 — OnDestroy 中对称 Release
public class BattleManager : MonoBehaviour {
List<AsyncOperationHandle<GameObject>> handles = new();
async void SpawnEnemy(string key) {
var h = Addressables.LoadAssetAsync<GameObject>(key);
await h.Task;
handles.Add(h);
Instantiate(h.Result, spawnPos, Quaternion.identity);
}
void OnDestroy() {
foreach (var h in handles) {
Addressables.Release(h); // ✅ 对称释放,引用计数归零,资源可被卸载
}
handles.Clear();
}
}反例:UI 精灵没打图集,Draw Call 爆炸
# 反例 — 每个图标单独一张纹理
Assets/UI/Icons/
sword_icon.png (独立纹理,1 Draw Call)
shield_icon.png (独立纹理,1 Draw Call)
potion_icon.png (独立纹理,1 Draw Call)
... 80 个图标 = 80 个 Draw Call ❌
# 正例 — 打成图集,共享同一纹理
Assets/UI/Atlas/
BattleHUD_Atlas.png (1 张图集,包含所有战斗 HUD 图标,1 Draw Call ✅)自查清单
- 所有大资源(纹理、音频、预制体、场景)走异步加载接口,主线程没有同步 Load 调用。
- 每个
LoadAssetAsync都有对应的Release,且在对象销毁或场景卸载时被调用到。 - UI 精灵已按模块打图集,没有大量散图直接引用;图集大小未超过 2048×2048。
- 各平台纹理压缩格式已设置(非 RGBA32 全平台默认),通过 Texture Overview 工具确认。
- 所有事件监听、委托订阅在对象 OnDisable/OnDestroy 中有对称的反注册。
- 项目有明确的内存与包体预算文档,且在最近一次里程碑节点用 Profiler 验证未超预算。
- 内存峰值测试在战斗中场景最复杂时刻(而非菜单/大厅)在目标低端设备上完成过。
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

