Hidlibrary: ReadReport () утечка памяти

Созданный на 14 авг. 2011  ·  9Комментарии  ·  Источник: mikeobrien/HidLibrary

Отличная библиотека Майк, большое спасибо за эту огромную работу.

Проблема в том, что я хочу заполнить InputReport данными:

InputReport = device.ReadReport ();

где InputReport:

HidLibrary.HidReport InputReport = новый HidLibrary.HidReport (device.Capabilities.InputReportByteLength);

Это очень большая утечка памяти, особенно когда я читаю отчеты в асинхронном режиме с устройства (например, 100 раз в секунду). За несколько минут это может занять сотни мегабайт.

Я новичок в программировании на C # и не нашел решения проблемы, описанной выше; (

Приветствую!

Самый полезный комментарий

Вот мой предлагаемый способ решения проблемы с производительностью, которую заметил Качарт (и я):
https://github.com/macaba/HidLibrary/commit/8f1864e1351ccca4772d5bbc18a0f94d7ba07fe7

Использование происходит по следующим направлениям:

device.ConnectionCheckOverride = device.IsConnected;
methodRequiringFasterUSBReadWrite();
device.ConnectionCheckOverride = false;

Это сократило время выполнения моего тестового примера для массовой передачи данных по USB с 159 до 47 секунд.

Мне не нравилось решение kaczart просто потому, что свойство IsConnected используется в HidDeviceEventMonitor, поэтому необходимо сохранить исходную функциональность перечисления подключенных в данный момент USB-устройств. Проще говоря; Я не думаю, что события Inserted и Removed когда-либо будут вызываться в коде kaczart (после беглого просмотра).

Все 9 Комментарий

Качарт,

К сожалению, этот код довольно старый, и у меня не было времени дать его
любой ТСХ. На данный момент у меня есть это только для справки. Ты лучший
ставка на форк / улучшение.

м

В вс, 14 августа 2011 г., 10:37, kaczart <
[email protected]> написал:

Отличная библиотека Майк, большое спасибо за эту огромную работу.

Проблема в том, что я хочу заполнить InputReport данными:

InputReport = device.ReadReport ();

где InputReport:

HidLibrary.HidReport InputReport = новый
HidLibrary.HidReport (ukp.Capabilities.InputReportByteLength);

Это очень большая утечка памяти, особенно когда я читаю отчеты в асинхронном режиме.
режим с устройства (например, 100 раз в секунду). Через несколько минут это может
занимает сотни мегабайт.

Я новичок в программировании на C # и не нашел решения проблемы
описанный выше; (

Приветствую!

Ответьте на это письмо напрямую или просмотрите его на GitHub:
https://github.com/mikeobrien/HidLibrary/issues/11

Качарт,

Вы нашли решение? Я просто заметил то же самое.
Отличная библиотека Майк, большое спасибо! Я работаю с USB-шкалой Endicia, и это довольно весело.

jrockfl,

к сожалению, у меня не было времени и навыков, чтобы исправить эту проблему :(

Приветствую

Проблема в том, что HidReport и Devicedata не освобождены, поэтому они ждут сборки мусора.
Это простое решение - выпустить его после того, как он будет обработан ...

Наконец мне пришлось исправить эту проблему, и я делюсь тем, что нашел.

1) Прежде всего, каждый метод чтения / записи в библиотеке проверяет, подключено ли устройство, что требует больших затрат производительности, потому что метод IsConnected вызывает каждый раз EnumerateHidDevices (). На практике, когда я отправляю большой пакет данных с устройства, хост ПК работает медленнее, чем устройство HID, и некоторые пакеты теряются из-за ограниченного кольцевого буфера (32 отчета по умолчанию, может быть увеличено до 512, но это не окончательное решение).
пс. Вы можете расширить свой кольцевой буфер с 32 до 512 отчетов, позвонив:
NativeMethods .HidD_SetNumInputBuffers ((int) device.ReadHandle, 512); // Это будет работать для XP и более поздних версий.
2) Во-вторых, в EnumerateHidDevices () есть ОГРОМНАЯ утечка памяти из-за "yield return devicePath;" в строке 69 и NativeMethods.SetupDiDestroyDeviceInfoList (deviceInfoSet); никогда не назовут.

Мое решение:
1) Не вызывайте IsConnected при каждом чтении / записи. Сделайте дополнительную переменную isConnected в HidDevice:
public bool isConnected;
Установите для переменной значение true после успешного подключения (например, в вашей функции Connect ()):
device.isConnected = true;
Обновляйте его во всех событиях DeviceEventMonitorInserted () и DeviceEventMonitorRemoved (), например:
if (Inserted! = null) Inserted ();
заменить:
если (вставлено! = ноль)
{
isConnected = true;
Вставлено ();
}
а также:
если (Удалено! = null) Удалено ();
заменить:
if (Удалено! = null)
{
isConnected = false;
Удаленный();
}
Затем проверяйте эту переменную при каждой функции вызова чтения / записи:
if (isConnected) вместо if (IsConnected)
Каждый раз, когда вам нужно проверить, подключено ли устройство, проверяйте состояние публичной переменной isConnected. У меня работает - загрузка процессора 0-1% вместо 10-20% для потока чтения.

2) в HidDevice.cs строку # 69 удалите:
// yield return devicePath;
Это позволит NativeMethods .SetupDiDestroyDeviceInfoList (deviceInfoSet); называться должным образом.
Затем после NativeMethods .SetupDiDestroyDeviceInfoList (deviceInfoSet) добавьте:
foreach (строка devicePath в устройствах)
yield return devicePath;
Это исправит ОГРОМНУЮ утечку памяти (в моем случае около 256 МБ на каждый 1 МБ полученных данных)

Надеюсь, это хепс.

круто, спасибо за подсказки, kaczart !!!

Вот мой предлагаемый способ решения проблемы с производительностью, которую заметил Качарт (и я):
https://github.com/macaba/HidLibrary/commit/8f1864e1351ccca4772d5bbc18a0f94d7ba07fe7

Использование происходит по следующим направлениям:

device.ConnectionCheckOverride = device.IsConnected;
methodRequiringFasterUSBReadWrite();
device.ConnectionCheckOverride = false;

Это сократило время выполнения моего тестового примера для массовой передачи данных по USB с 159 до 47 секунд.

Мне не нравилось решение kaczart просто потому, что свойство IsConnected используется в HidDeviceEventMonitor, поэтому необходимо сохранить исходную функциональность перечисления подключенных в данный момент USB-устройств. Проще говоря; Я не думаю, что события Inserted и Removed когда-либо будут вызываться в коде kaczart (после беглого просмотра).

Проверка подключения устройства при каждом чтении и записи является основным узким местом производительности в высокочастотных приложениях. В моем конкретном случае было в 30 раз быстрее предположить, что устройство подключено, а не перепроверять подключение устройства; круговые поездки упали с 70 мс до 2 мс.

Поэтому я просто написал пару методов расширения для обработки моего собственного ввода-вывода для быстрого использования пула:

        [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;
            }
        }
Была ли эта страница полезной?
0 / 5 - 0 рейтинги