伟大的图书馆迈克,非常感谢这项巨大的工作。
问题是当我想用数据填充 InputReport 时:
InputReport = device.ReadReport();
其中 InputReport 是:
HidLibrary.HidReport InputReport = new HidLibrary.HidReport(device.Capabilities.InputReportByteLength);
这是一个非常大的泄漏内存,特别是当我以异步模式从设备读取报告时(例如,每秒 100 次)。 在几分钟内,它可能需要数百兆字节。
我是 c# 编程的初学者,没有找到上面描述的问题的解决方案;(
你好!
卡扎特,
不幸的是,该代码很旧,我没有时间提供它
任何薄层色谱。 在这一点上,我只是把它作为参考。 尽力而为
打赌是分叉/改进。
米
2011 年 8 月 14 日星期日上午 10:37,kaczart <
回复@reply.github.com>写道:
伟大的图书馆迈克,非常感谢这项巨大的工作。
问题是当我想用数据填充 InputReport 时:
InputReport = device.ReadReport();
其中 InputReport 是:
HidLibrary.HidReport InputReport = 新
HidLibrary.HidReport(ukp.Capabilities.InputReportByteLength);这是一个非常大的泄漏内存,特别是当我以异步方式阅读报告时
来自设备的模式(例如,每秒 100 次)。 几分钟就可以
需要数百兆字节。我是 c# 编程的初学者,没有找到问题的解决方案
上面描述;(你好!
直接回复此邮件或在 GitHub 上查看:
https://github.com/mikeobrien/HidLibrary/issues/11
卡扎特,
你找到解决办法了吗? 我只是注意到了同样的事情。
很棒的图书馆迈克,非常感谢! 我正在使用 Endicia USB 秤,这很有趣。
杰罗克弗尔,
不幸的是,我没有时间也没有足够的技能来解决这个问题:(
你好
问题是 HidReport 和 Devicedata 没有被释放,所以它等待垃圾回收。
尽管在处理完后将其释放,但这是一个简单的修复...
最后我不得不解决这个问题,我分享了我的发现
1) 首先,库中的每一个读/写方法都会检查设备是否连接,这会消耗大量性能,因为每次 EnumerateHidDevices() 都会调用 IsConnected 方法。 实际上,当我从设备发送大包数据时,PC Host 比 HID 设备慢,并且由于有限的环形缓冲区而丢失了一些数据包(默认为 32 个报告,可以扩展到 512 个,但这不是最终解决方案)。
附: 您可以将环形缓冲区从 32 个扩展到最多 512 个报告调用:
NativeMethods .HidD_SetNumInputBuffers((int )device.ReadHandle, 512); //它适用于XP及更高版本。
2) 其次,在 EnumerateHidDevices() 中由于“yield return devicePath;”而导致巨大的内存泄漏; 在第 69 行和 NativeMethods.SetupDiDestroyDeviceInfoList(deviceInfoSet); 永远不会被调用。
我的解决方案:
1) 不要在每次读/写时调用 IsConnected。 在 HidDevice 中创建额外的 isConnected 变量:
public bool isConnected;
成功连接后将变量设置为 true(例如在您的 Connect() 函数中):
device.isConnected = true;
在每个 DeviceEventMonitorInserted() 和 DeviceEventMonitorRemoved() 事件中更新它,例如:
如果(插入!= null)插入();
用。。。来代替:
如果(插入!= null )
{
isConnected = true;
插入();
}
和:
if (Removed != null ) Removed();
用。。。来代替:
如果(已删除!= null )
{
isConnected = false ;
删除();
}
比每个读/写调用函数检查这个变量:
if (isConnected) 而不是 if (IsConnected)
每次需要检查设备是否已连接时,请检查公共变量 isConnected 的状态。 它对我有用 - 0-1% 的处理器使用率而不是 10-20% 的读取线程。
2) 在 HidDevice.cs 第 69 行删除:
//产量返回设备路径;
它将允许 NativeMethods .SetupDiDestroyDeviceInfoList(deviceInfoSet); 被称为propetly。
接下来,在 NativeMethods .SetupDiDestroyDeviceInfoList(deviceInfoSet) 之后添加:
foreach(设备中的字符串设备路径)
收益率返回设备路径;
它将修复巨大的内存泄漏(在我的情况下,每接收 1MB 数据大约 256MB)
希望它heps。
太棒了,感谢您的提示,kaczart !!!
这是我针对 kaczart(和我)注意到的性能问题建议的解决方法:
https://github.com/macaba/HidLibrary/commit/8f1864e1351ccca4772d5bbc18a0f94d7ba07fe7
用法如下:
device.ConnectionCheckOverride = device.IsConnected;
methodRequiringFasterUSBReadWrite();
device.ConnectionCheckOverride = false;
这将我的批量 USB 传输测试用例执行时间从 159 秒减少到 47 秒。
我并不热衷于 kaczart 的解决方案,仅仅是因为在 HidDeviceEventMonitor 中使用了 IsConnected 属性,因此需要保留枚举当前连接的 USB 设备的原始功能。 简单的说; 我认为在kaczart 的代码中永远不会调用Inserted 和Removed 事件(简要介绍一下)。
在每次读取和写入时检查设备连接是高频应用程序中的主要性能瓶颈。 在我的特定情况下,假设设备已连接而不是重新检查设备连接要快 30 倍; 往返时间从大约 70 毫秒下降到 2 毫秒。
所以我只是写了几个扩展方法来处理我自己的 IO 以快速池使用:
[DllImport("hid.dll", SetLastError = true)]
static internal extern bool HidD_SetOutputReport(IntPtr hidDeviceObject, byte[] lpReportBuffer, int reportBufferLength);
[DllImport("kernel32.dll", SetLastError = true)]
static internal extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
public static bool FastWrite(this HidLibrary.HidDevice device, byte[] outputBuffer)
{
try
{
if (NativeMethods.HidD_SetOutputReport(device.Handle, outputBuffer, outputBuffer.Length))
return true;
else
return false;
}
catch
{
return false;
}
}
public static ReadStatus FastRead(this HidLibrary.HidDevice device, byte[] inputBuffer)
{
try
{
uint bytesRead;
if (NativeMethods.ReadFile(device.Handle, inputBuffer, (uint)inputBuffer.Length, out bytesRead, IntPtr.Zero))
{
return ReadStatus.Success;
}
else
{
return ReadStatus.NoDataRead;
}
}
catch (Exception)
{
return ReadStatus.ReadError;
}
}
最有用的评论
这是我针对 kaczart(和我)注意到的性能问题建议的解决方法:
https://github.com/macaba/HidLibrary/commit/8f1864e1351ccca4772d5bbc18a0f94d7ba07fe7
用法如下:
这将我的批量 USB 传输测试用例执行时间从 159 秒减少到 47 秒。
我并不热衷于 kaczart 的解决方案,仅仅是因为在 HidDeviceEventMonitor 中使用了 IsConnected 属性,因此需要保留枚举当前连接的 USB 设备的原始功能。 简单的说; 我认为在kaczart 的代码中永远不会调用Inserted 和Removed 事件(简要介绍一下)。