执行多线程方法会产生垃圾。为什么会这样,我们可以阻止它吗?
ThreadPool.QueueUserWorkItem(callBack, state);
修改 垃圾我指的是创建的对象然后超出了范围。垃圾收集非常慢,因为它的旧版单声道。所以你从GC中保存的每一个kb都是一个胜利。如果您不熟悉统一引擎,请在屏幕截图中查看突出显示行上的GC列。它说0.6kb。因此它创建了600字节的垃圾。回调代码没有创建任何垃圾,所以这是根据ThreadPool.QueueUserWorkItem
编辑2:这里进一步详细说明是一个更具体的例子:
public class TestThread : MonoBehaviour
{
public void Update()
{
if (Time.frameCount%10 == 0)
ThreadPool.QueueUserWorkItem(DummyMethod);
}
public void DummyMethod(object meaningless)
{
}
}
结果如下。请查看突出显示的行。 GC栏显示285Bytes。由于DummyMethod没有做任何事情,垃圾与ThreadPool有关。
编辑3: 为了放松这种情况并找到替代方案,可以使用从队列中执行作业的工作线程。
没关系但是如果有多个CPU可用,那么必须运行在CPU以外的CPU上。 Unity几乎可以在一个线程中执行任何操作,因此同一CPU上的后台工作人员将成为灾难。它也是一个跨平台项目,因此仅限Windows的解决方案将无法运行。所以基本上我需要一个工作线程解决方案,并知道是否可以实现线程的CPU是否与另一个线程相同。
答案 0 :(得分:5)
当你ThreadPool.QueueUserWorkItem(DummyMethod);
实际隐含地将你的代码转换为ThreadPool.QueueUserWorkItem(new WaitCallback(DummyMethod));
时,该回调可能是被放到GC上的项目。尝试以下代码以显式创建委托并保留对它的引用,并查看它是否减少了GCable数据的数量。
public class TestThread : MonoBehaviour
{
private readonly WaitCallback _callback;
public TestThread()
{
_callback = new WaitCallback(DummyMethod);
}
public void Update()
{
if (Time.frameCount%10 == 0)
ThreadPool.QueueUserWorkItem(_callback);
}
public void DummyMethod(object meaningless)
{
}
}
更新:以下是单线程后台工作程序的一个非常基本的实现,为您提供一个起点。下面的代码是未经测试的,可能会表现得非常糟糕,但它确实会给你一个想法作为起点。
public class BasicBackgroundWorker
{
private readonly Thread _backgroundWorkThread;
private readonly Queue<Action> _queue = new Queue<Action>();
private readonly ManualResetEvent _workAvailable = new ManualResetEvent(false);
public BasicBackgroundWorker()
{
_backgroundWorkThread = new Thread(BackgroundThread)
{
IsBackground = true,
Priority = ThreadPriority.BelowNormal,
Name = "BasicBackgroundWorker Thread"
};
_backgroundWorkThread.Start();
}
public void EnqueueWork(Action work)
{
lock (_queue)
{
_queue.Enqueue(work);
_workAvailable.Set();
}
}
private void BackgroundThread()
{
while (true)
{
_workAvailable.WaitOne();
Action workItem;
lock (_queue)
{
workItem = _queue.Dequeue();
if (_queue.Count == 0)
{
_workAvailable.Reset();
}
}
try
{
workItem();
}
catch (Exception ex)
{
//Log exception that happened in backgroundWork
}
}
}
}