You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity运行100个小球下落实验频繁停止,修改IO代码仍冻结如何解决

问题根本原因

你遇到的Unity冻结和内存无关,是同步IO阻塞主线程导致的:

  • Unity所有游戏逻辑默认运行在主线程,100个小球实例同时/频繁调用File相关的同步方法,磁盘IO速度远低于CPU运算速度,直接阻塞主线程导致程序无响应
  • 单小球场景下IO压力小所以无异常,多小球场景下IO操作数指数级上升,运行时间越长累计阻塞时间越长就会触发冻结
  • 之前的多个版本代码都是单实例独立写文件,频繁创建释放文件句柄、磁盘寻址都会进一步增加IO开销

单文件稳定运行方案

用全局唯一的管理类统一收集所有小球数据,批量写入单文件,从根源上降低IO压力。

第一步:全局数据管理类(挂载到场景中唯一的全局空对象上即可)

using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class FallDataManager : MonoBehaviour
{
    public static FallDataManager Instance { get; private set; }

    // 小球数据缓存队列
    private readonly List<string> _ballDataCache = new List<string>();
    // 单文件存储路径
    private string _saveFilePath;
    // 写盘间隔(单位:帧),可根据数据精度需求调整
    [SerializeField] private int _writeIntervalFrame = 10;
    private int _frameCounter = 0;

    private void Awake()
    {
        // 单例初始化
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);

        // 初始化存储路径,默认存在Unity持久化目录,可自行修改
        _saveFilePath = Path.Combine(Application.persistentDataPath, "ball_fall_record.txt");
        // 启动时清空旧日志,不需要可删除此行
        File.WriteAllText(_saveFilePath, "小球下落实验数据记录\r\n");
    }

    // 对外提供的数据上报接口,供小球脚本调用
    public void UploadBallData(string data)
    {
        lock (_ballDataCache)
        {
            _ballDataCache.Add(data);
        }
    }

    private void LateUpdate()
    {
        _frameCounter++;
        if (_frameCounter >= _writeIntervalFrame)
        {
            _frameCounter = 0;
            FlushCacheToFile();
        }
    }

    // 批量写入缓存数据到文件
    private void FlushCacheToFile()
    {
        lock (_ballDataCache)
        {
            if (_ballDataCache.Count == 0) return;
            File.AppendAllLines(_saveFilePath, _ballDataCache);
            _ballDataCache.Clear();
        }
    }

    // 程序退出时写入剩余未保存的缓存数据
    private void OnApplicationQuit()
    {
        FlushCacheToFile();
    }
}

第二步:小球挂载的逻辑脚本(无需自己写文件,仅上报数据即可)

using UnityEngine;

public class BallController : MonoBehaviour
{
    // 小球编号,实例化小球时自行赋值即可
    public int ballNum;

    // 在你需要记录数据的时机调用该方法(比如每帧更新、小球触地时)
    private void RecordFallData()
    {
        // 按需求拼接数据格式,示例格式为:小球编号,位置X,位置Y,位置Z,运行时间
        string record = $"{ballNum},{transform.position.x:F3},{transform.position.y:F3},{transform.position.z:F3},{Time.time:F2}";
        FallDataManager.Instance.UploadBallData(record);
    }
}

方案优势

  • 全程仅生成单个记录文件,完全消除多文件操作的额外开销
  • 批量降频写盘大幅减少IO操作次数,不会阻塞主线程
  • 加锁保证线程安全,后续可直接扩展异步写入进一步降低性能损耗

内容的提问来源于stack exchange,提问作者Emma Lim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 21:45:08