一、IL2CPP内存管理特性与泄漏根源
1. IL2CPP内存架构特点
| 内存区域 |
管理方式 |
常见泄漏类型 |
| 托管堆(Managed) |
GC自动回收 |
静态引用/事件订阅未取消 |
| 原生堆(Native) |
手动管理 |
非托管资源未释放 |
| 桥接层 |
GCHandle/PInvoke |
跨语言引用未正确释放 |
2. 典型泄漏场景分析
// 案例1:静态变量持有对象
public class GameManager {
public static List<Enemy> AllEnemies = new List<Enemy>();
// 敌人销毁时未从列表移除将导致泄漏
}
// 案例2:未取消的事件订阅
void OnEnable() {
EventManager.OnBattleEnd += HandleBattleEnd;
}
void OnDisable() {
EventManager.OnBattleEnd -= HandleBattleEnd; // 若未执行将泄漏
}
// 案例3:非托管资源未释放
public class NativePluginWrapper : IDisposable {
private IntPtr _nativePtr;
~NativePluginWrapper() {
if(_nativePtr != IntPtr.Zero) {
// 需调用NativeFree(_nativePtr);
}
}
}
二、Memory Profiler深度配置
1. 内存快照捕获配置
// 运行时主动捕获快照
using UnityEngine.Profiling.Memory.Experimental;
public class MemorySnapshotTrigger : MonoBehaviour {
[SerializeField] KeyCode _snapshotKey = KeyCode.F12;
void Update() {
if(Input.GetKeyDown(_snapshotKey)) {
CaptureSnapshot();
}
}
static void CaptureSnapshot() {
MemoryProfiler.TakeSnapshot(
"snapshot_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".snap",
(success, path) => Debug.Log($"Snapshot saved: {path} (success:{success})")
);
}
}
2. IL2CPP符号文件生成
# 构建时生成完整符号文件
BuildPlayerOptions buildOptions = new BuildPlayerOptions();
buildOptions.opt