C#禁用USB ReadPipe的垃圾回收

我试图使用FTDI的D3XX.NET从USB端口收集数据。 收集数据,然后将其发送到快速傅立叶变换以绘制光谱。 即使您错过了一些数据,这也可以正常工作。 你不能说。 但是,如果您希望将此数据发送到音频输出组件,则会发现数据丢失。 这就是我的问题所在。 收集数据然后将其发送到音频设备。 所有数据包都在所需的时间范围内完成。 但是,音频正在丢弃它出现的数据。 这是一张正弦波在音频输出中的样子:

在此处输入图像描述

您可以看到一些数据在开始时丢失,并且似乎在结束时缺少整个周期。 这只是一个例子,它一直在变化。 有时似乎数据不存在。 我已经完成了整个处理链,我非常确定声音的数据包正在制作它。 我已经使用过JetBrains性能分析器。 我发现如下:ReadPipe方法需要8.5ms,这正是您期望读取的内容。 到现在为止还挺好。 ReadPipe命令完成后,您有0.5ms的时间来执行另一个ReadPipe,否则您将丢失一些数据。 查看分析器输出,我看到:

在此处输入图像描述

ReadPipe需要8.5ms,然后有这个垃圾收集条目,平均需要1.6ms。 如果这确实偶尔发生,那么我丢失了一些数据。

所以这是代码:它是一个后台工作者:

private void CollectData(object sender, DoWorkEventArgs e) { while (keepGoing) { ftStatus = d3xxDevice.ReadPipe(0x84, iqBuffer, 65536, ref bytesTransferred); //read IQ data - will get 1024 pairs - 2 bytes per value _waitForData.Set(); } } 

waithandle向另一个线程表示数据可用。 那么GC是数据丢失的原因吗? 如果是这样,我该如何避免这种情况? 谢谢!

如果您可以确认内存不足,可以尝试将GCSettings.LatencyMode设置为GCLatencyMode.SustainedLowLatency 。 这将阻止某些阻塞垃圾收集发生,除非您的内存不足。 有关更多详细信息和限制,请查看有关延迟模式的文档 。

如果垃圾收集对您的用例仍然具有太大的破坏性并且您使用的是.NET 4.6或更高版本,则可以尝试调用GC.TryStartNoGCRegion 。 此方法将尝试保留足够的内存以分配指定的数量,并阻止GC直到您用完预留。 如果您的内存使用率相当一致,那么您可以通过传递足够大的值来适应应用程序的使用,但无法保证呼叫成功。

如果您使用的是不支持其中任何一种的旧版本的.NET,那么您可能会运气不好。 如果这是一个GUI应用程序(它看起来像是由事件处理程序判断),则对分配没有足够的控制权。

另一件需要考虑的事情是,对于不能容忍中断的应用程序,C#并不是真正的工具。 如果您熟悉编写本机代码,则可以在未管理的线程上执行时间敏感的工作; 据我所知,这是唯一可靠的解决方案,特别是如果您的应用程序将在最终用户计算机上运行。

您需要对垃圾收集器更友好,而不是分配太多。

简而言之,如果您的GC停止了线程,则会出现垃圾问题。 GC将暂停所有线程以进行清理,除了可以更好地管理您创建的垃圾之外,没有什么可以真正做到的。

如果你有数组,不要不断地创建它们,而是重复使用它们(依此类推)。 使用较轻的结构,使用允许您减少分配的工具,如SpanMemory 。 如果您的代码严重async ,请考虑使用较少的awaits ,并且不要将它们放在循环中。 通过ref并使用ref本地等,如果可以,也远离大型非托管数据块。

此外,在无关紧要的任何停机时间调用GC.Collect可能是有益的,尽管更好的设计可能会更有益。