有没有办法防止ThreadPool制造垃圾?

执行multithreading方法会产生垃圾。 为什么会这样,我们可以阻止它吗?

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是否与另一个线程相同。

当你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 _queue = new Queue(); 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 } } } }