Hidlibrary: Vazamento de memória ReadReport ()

Criado em 14 ago. 2011  ·  9Comentários  ·  Fonte: mikeobrien/HidLibrary

Ótima biblioteca Mike, muito obrigado por este enorme trabalho.

O problema é quando quero preencher InputReport com dados:

InputReport = device.ReadReport ();

onde InputReport é:

HidLibrary.HidReport InputReport = novo HidLibrary.HidReport (device.Capabilities.InputReportByteLength);

É uma perda de memória muito grande, especialmente quando leio relatórios no modo assíncrono do dispositivo (por exemplo, 100 vezes por segundo). Em poucos minutos, pode levar centenas de megabytes.

Sou iniciante em programação c # e não encontrei solução para o problema descrito acima; (

saudações!

Comentários muito úteis

Aqui está minha solução alternativa sugerida para o problema de desempenho que kaczart (e eu) notamos:
https://github.com/macaba/HidLibrary/commit/8f1864e1351ccca4772d5bbc18a0f94d7ba07fe7

O uso segue as linhas de:

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

Isso reduziu o tempo de execução do meu caso de teste de transferência de USB em massa de 159 segundos para 47 segundos.

Eu não estava interessado na solução de kaczart simplesmente porque a propriedade IsConnected é usada em HidDeviceEventMonitor, então precisava manter a funcionalidade original de enumerar dispositivos USB atualmente conectados. Basta colocar; Eu não acho que os eventos Inseridos e Removidos serão chamados no código do kaczart (por uma breve olhada nele).

Todos 9 comentários

Kaczart,

Infelizmente, esse código é muito antigo e não tive tempo de fornecê-lo
qualquer TLC. Neste ponto, eu apenas o tenho como referência. Seu melhor
aposta é bifurcar / melhorar.

m

No domingo, 14 de agosto de 2011 às 10:37, kaczart <
[email protected]> escreveu:

Ótima biblioteca Mike, muito obrigado por este enorme trabalho.

O problema é quando quero preencher InputReport com dados:

InputReport = device.ReadReport ();

onde InputReport é:

HidLibrary.HidReport InputReport = novo
HidLibrary.HidReport (ukp.Capabilities.InputReportByteLength);

É um grande vazamento de memória, especialmente quando leio relatórios em assíncrono
modo do dispositivo (por exemplo, 100 vezes por segundo). Em poucos minutos pode
leva centenas de megabytes.

Sou iniciante em programação c # e não encontrei solução para o problema
descrito acima; (

saudações!

Responda a este e-mail diretamente ou visualize-o no GitHub:
https://github.com/mikeobrien/HidLibrary/issues/11

Kaczart,

Você encontrou uma solução? Acabei de notar a mesma coisa.
Ótima biblioteca Mike, muito obrigado! Estou trabalhando com uma escala usb Endicia e isso é muito divertido.

jrockfl,

infelizmente, não tive tempo nem habilidade suficiente para corrigir esse problema :(

saudações

O problema é que o HidReport e o Devicedata não são liberados, então ele aguarda uma coleta de lixo.
É uma solução fácil, no entanto, liberá-lo depois de ser processado ...

Finalmente, tive que corrigir esse problema e compartilho o que descobri

1) Em primeiro lugar, cada método Read / Write na biblioteca verifica se o dispositivo está conectado, o que custa muito desempenho porque o método IsConnected chama cada vez que EnumerateHidDevices (). Na prática, quando envio um grande pacote de dados do dispositivo, o PC Host é mais lento do que o dispositivo HID e alguns pacotes são perdidos devido ao buffer de anel limitado (32 relatórios por padrão, podem ser estendidos para 512, mas não é a solução final).
ps. você pode estender seu buffer de anel de 32 para no máximo 512 relatórios chamando:
NativeMethods .HidD_SetNumInputBuffers ((int) device.ReadHandle, 512); // Funcionará para XP e versões posteriores.
2) Em segundo lugar, em EnumerateHidDevices () há um ENORME vazamento de memória devido a "yield return devicePath;" na linha 69 e NativeMethods.SetupDiDestroyDeviceInfoList (deviceInfoSet); nunca será chamado.

Minha solução:
1) Não chame IsConnected a cada leitura / gravação. Crie uma variável isConnected adicional em HidDevice:
public bool isConnected;
Defina a variável como verdadeira após a conexão bem-sucedida (por exemplo, em sua função Connect ()):
device.isConnected = true;
Atualize-o em todos os eventos DeviceEventMonitorInserted () e DeviceEventMonitorRemoved (), por exemplo:
if (inserido! = nulo) Inserted ();
substituir com:
if (inserido! = nulo)
{
isConnected = true;
Inserido ();
}
e:
if (Removido! = nulo) Removido ();
substituir com:
if (removido! = nulo)
{
isConnected = false;
Removido();
}
Em seguida, verifique esta variável a cada função de chamada de leitura / gravação:
if (isConnected) em vez de if (IsConnected)
Sempre que você precisar verificar se o dispositivo está conectado, verifique o estado da variável pública isConnected. Funciona para mim - 0-1% de uso do processador em vez de 10-20% para o thread de leitura.

2) na linha HidDevice.cs # 69, exclua:
// rendimento return devicePath;
Isso permitirá NativeMethods .SetupDiDestroyDeviceInfoList (deviceInfoSet); ser chamado apropriadamente.
Em seguida, depois de NativeMethods .SetupDiDestroyDeviceInfoList (deviceInfoSet), adicione:
foreach (string devicePath em dispositivos)
yield return devicePath;
Ele corrigirá o enorme vazamento de memória (cerca de 256 MB para cada 1 MB de dados recebidos no meu caso)

Espero que ajude.

incrível, obrigado pelas suas dicas, kaczart !!!

Aqui está minha solução alternativa sugerida para o problema de desempenho que kaczart (e eu) notamos:
https://github.com/macaba/HidLibrary/commit/8f1864e1351ccca4772d5bbc18a0f94d7ba07fe7

O uso segue as linhas de:

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

Isso reduziu o tempo de execução do meu caso de teste de transferência de USB em massa de 159 segundos para 47 segundos.

Eu não estava interessado na solução de kaczart simplesmente porque a propriedade IsConnected é usada em HidDeviceEventMonitor, então precisava manter a funcionalidade original de enumerar dispositivos USB atualmente conectados. Basta colocar; Eu não acho que os eventos Inseridos e Removidos serão chamados no código do kaczart (por uma breve olhada nele).

Verificar a conexão de um dispositivo em cada leitura e gravação é um grande gargalo de desempenho em aplicativos de alta frequência. No meu caso específico, foi 30x mais rápido presumir que o dispositivo estava conectado em vez de verificar novamente a conexão do dispositivo; viagens de ida e volta caíram de cerca de 70ms para 2ms.

Então, acabei de escrever alguns métodos de extensão para lidar com meu próprio IO para uso rápido de pool:

        [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;
            }
        }
Esta página foi útil?
0 / 5 - 0 avaliações