Unity手动GC,解决资源加载引发内存溢出问题
玩游戏的时候爆内存了,发现罪魁祸首是播放器内存溢出,在此记录一下解决方案 :-)
什么是内存溢出?
内存溢出(OutOfMemoryError,简称OOM)是指程序在申请内存时,系统没有足够的空闲内存空间供其使用,导致程序运行失败的现象。这是软件开发中常见的严重错误之一。
为什么会存在内存溢出?
程序运行需要内存(如创建对象、加载数据),但当发生以下情况时会触发内存溢出:
- 内存泄漏(Memory Leak)
- 程序申请内存后未释放(如未被回收的对象持续累积)。
- 例如:静态集合类持续添加数据、未关闭数据库连接、未注销事件监听。
- 数据量过大
- 一次性加载超大规模数据(如大文件、海量数据库查询结果)。
- 内存设置不足
- 应用所需内存超过JVM堆上限(如未调整默认的JVM堆大小)。
- 无限递归/循环
本文主要解决的是由于内存泄漏导致的内存溢出问题,而解决这个问题也很简单,在合适的时机手动触发GC,回收掉内存即可很好的避免内存泄漏。
接下来将以我的播放器为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public IEnumerator LoadAndPlayMusic(string path) { using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip("file://" + path, AudioType.UNKNOWN)) { yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError) { Debug.LogError("加载音频时发生错误: " + www.error); } else { audioSource.clip = DownloadHandlerAudioClip.GetContent(www); audioSource.Play(); isPlaying = true; Debug.Log("开始播放: " + path); PlayBarHandel.GetComponent<Animator>().SetTrigger("IntoPlaying"); CtrlButton.SetTrigger("Pause"); } } }
|
这段代码看似没有问题,实际运行下来会发现:

为什么播放器内存占用会这么大?实际上这就是在读取音频文件后一直没有释放掉导致的
找到问题所在,那么解决起来就很容易了,只需要在每次读取新的音频之前手动GC一次,回收掉所有加载的音频就能解决了,为此封装一个简单的内存回收功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| private IEnumerator ReleasePreviousClip() { if (audioSource.clip != null) { audioSource.Stop();
audioSource.clip.UnloadAudioData();
Destroy(audioSource.clip); audioSource.clip = null;
var unloadOp = Resources.UnloadUnusedAssets(); yield return unloadOp;
System.GC.Collect(); } }
|
接下来在每次加载新的音频前调用,回收资源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public IEnumerator LoadAndPlayMusic(string path) { yield return StartCoroutine(ReleasePreviousClip()); using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip("file://" + path, AudioType.UNKNOWN)) { yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError) { Debug.LogError("加载音频时发生错误: " + www.error); } else { audioSource.clip = DownloadHandlerAudioClip.GetContent(www); audioSource.Play(); isPlaying = true; Debug.Log("开始播放: " + path); PlayBarHandel.GetComponent<Animator>().SetTrigger("IntoPlaying"); CtrlButton.SetTrigger("Pause"); } } }
|
[!CAUTION]
对于这种通过WWW方式获取的音频资源,在执行回收时会被释放,如果在加载之后再执行回收,会因为刚加载音频资源被回收导致无法播放,因此对于部分方式加载的资源需要格外注意GC的时机,避免加载出错!

到这里,内存溢出的问题已解决!