Unity 2022场景内存分配器溢出问题求助(关联SaveLoadManager脚本)
问题:Unity 2022内存分配器溢出,关联SaveLoadManager脚本
场景启动后触发致命错误:
Fatal Error! Overflow in memory allocator. UnityEngine.Rendering.RenderPipelineManager:DoRenderLoop_Internal (UnityEngine.Rendering.RenderPipelineAsset,intptr,UnityEngine.Object,Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle)
移除以下脚本后场景可正常运行,但需要保留该脚本功能:
public class SaveLoadManager : MonoBehaviour { private DatabaseReference databaseReference; public Transform player; private string userName; private float X; private float Y; private float Z; private float pos_x; private float pos_y; private float pos_z; private void Awake() { userName = PlayerPrefs.GetString("txt"); databaseReference = FirebaseDatabase.DefaultInstance.RootReference; LoadData(); } private void Start() { StartCoroutine(StartSaving()); } private void Update() { pos_x = player.position.x; pos_y = player.position.y; pos_z = player.position.z; } public void SaveData() { StartCoroutine(SavePlayerPosition()); } public void LoadData() { StartCoroutine(LoadPlayerPositionX()); StartCoroutine(LoadPlayerPositionY()); StartCoroutine(LoadPlayerPositionZ()); } IEnumerator SavePlayerPosition() { while (true) { var DBTask_0 = databaseReference.Child("users").Child(userName).Child("GameData").Child("position_x").SetValueAsync(pos_x); var DBTask_1 = databaseReference.Child("users").Child(userName).Child("GameData").Child("position_y").SetValueAsync(pos_y); var DBTask_2 = databaseReference.Child("users").Child(userName).Child("GameData").Child("position_z").SetValueAsync(pos_z); yield return new WaitUntil(predicate: () => DBTask_0.IsCompleted); if (DBTask_0.Exception != null) { Debug.LogWarning(message: $"Failed to register task with {DBTask_0.Exception}"); } yield return new WaitUntil(predicate: () => DBTask_1.IsCompleted); if (DBTask_1.Exception != null) { Debug.LogWarning(message: $"Failed to register task with {DBTask_1.Exception}"); } yield return new WaitUntil(predicate: () => DBTask_2.IsCompleted); if (DBTask_2.Exception != null) { Debug.LogWarning(message: $"Failed to register task with {DBTask_2.Exception}"); } } } IEnumerator LoadPlayerPositionX() { var DBTask = databaseReference.Child("users").Child(userName).Child("GameData").GetValueAsync(); yield return new WaitUntil(predicate: () => DBTask.IsCompleted); if (DBTask.Exception != null) { Debug.LogWarning(message: $"Failed to register task with {DBTask.Exception}"); } else { DataSnapshot dataSnapshot = DBTask.Result; X = float.Parse(dataSnapshot.Child("position_x").Value.ToString(), CultureInfo.InvariantCulture.NumberFormat); } } IEnumerator LoadPlayerPositionY() { var DBTask = databaseReference.Child("users").Child(userName).Child("GameData").GetValueAsync(); yield return new WaitUntil(predicate: () => DBTask.IsCompleted); if (DBTask.Exception != null) { Debug.LogWarning(message: $"Failed to register task with {DBTask.Exception}"); } else { DataSnapshot snapshot = DBTask.Result; Y = float.Parse(snapshot.Child("position_y").Value.ToString(), CultureInfo.InvariantCulture.NumberFormat); } } IEnumerator LoadPlayerPositionZ() { var DBTask = databaseReference.Child("users").Child(userName).Child("GameData").GetValueAsync(); yield return new WaitUntil(predicate: () => DBTask.IsCompleted); if (DBTask.Exception != null) { Debug.LogWarning(message: $"Failed to register task with {DBTask.Exception}"); } else { DataSnapshot snapshot = DBTask.Result; Z = float.Parse(snapshot.Child("position_z").Value.ToString(), CultureInfo.InvariantCulture.NumberFormat); } } IEnumerator StartSaving() { //yield return new WaitForSeconds(0.3f); //player.position = new Vector3(X, Y, Z); yield return new WaitForSeconds(1); SaveData(); } }
问题根源
- 无限循环无延迟:
SavePlayerPosition协程中的while (true)没有任何延迟,会在每一帧疯狂发起Firebase写请求,瞬间耗尽内存资源,触发分配器溢出。 - 冗余加载请求:三个加载协程各自独立请求
GameData节点,造成三次重复网络请求,额外消耗资源。 - 加载数据未生效:注释掉了设置玩家位置的代码,加载逻辑形同虚设。
修复方案
调整脚本逻辑,优化请求频率和资源占用:
using UnityEngine; using Firebase.Database; using System.Collections; using System.Globalization; public class SaveLoadManager : MonoBehaviour { private DatabaseReference databaseReference; public Transform player; private string userName; private Vector3 loadedPosition; private Vector3 currentPosition; private void Awake() { userName = PlayerPrefs.GetString("txt"); databaseReference = FirebaseDatabase.DefaultInstance.RootReference; StartCoroutine(LoadPlayerPosition()); } private void Start() { StartCoroutine(StartSavingLoop()); } private void Update() { currentPosition = player.position; } private IEnumerator StartSavingLoop() { // 等待1秒后开始保存 yield return new WaitForSeconds(1f); while (true) { SavePlayerPosition(); // 每5秒保存一次,可根据需求调整间隔 yield return new WaitForSeconds(5f); } } private void SavePlayerPosition() { var positionData = new PlayerPosition { position_x = currentPosition.x, position_y = currentPosition.y, position_z = currentPosition.z }; var dbTask = databaseReference.Child("users").Child(userName).Child("GameData").SetValueAsync(positionData); dbTask.ContinueWith(task => { if (task.Exception != null) { Debug.LogWarning($"保存位置失败: {task.Exception}"); } }); } private IEnumerator LoadPlayerPosition() { var dbTask = databaseReference.Child("users").Child(userName).Child("GameData").GetValueAsync(); yield return new WaitUntil(() => dbTask.IsCompleted); if (dbTask.Exception != null) { Debug.LogWarning($"加载位置失败: {dbTask.Exception}"); } else { DataSnapshot snapshot = dbTask.Result; if (snapshot.Exists) { loadedPosition.x = float.Parse(snapshot.Child("position_x").Value?.ToString() ?? "0", CultureInfo.InvariantCulture); loadedPosition.y = float.Parse(snapshot.Child("position_y").Value?.ToString() ?? "0", CultureInfo.InvariantCulture); loadedPosition.z = float.Parse(snapshot.Child("position_z").Value?.ToString() ?? "0", CultureInfo.InvariantCulture); // 延迟一帧设置位置,确保玩家对象初始化完成 yield return null; player.position = loadedPosition; } else { Debug.Log("未找到玩家位置数据,使用默认位置"); } } } // 用于序列化位置数据的类 private class PlayerPosition { public float position_x { get; set; } public float position_y { get; set; } public float position_z { get; set; } } }
关键修改说明
- 添加保存间隔:
StartSavingLoop协程控制每5秒保存一次,避免高频请求。 - 合并加载逻辑:单个协程完成位置加载,减少重复网络请求。
- 一次性提交位置数据:通过
PlayerPosition类序列化整个位置,单次请求完成保存,降低Firebase交互次数。 - 修复位置应用逻辑:加载完成后正确设置玩家位置,并增加空值判断避免解析错误。
- 移除冗余变量:简化位置存储变量,减少内存占用。
内容的提问来源于stack exchange,提问作者Kirill
相关产品推荐
相关产品推荐

