2017-06-06 2 views
0

Ich entdeckte ein Speicherleck lesen Daten über USB-Interrupt-Transfer mit libUSB synchron. Mein einfaches Benutzerprogramm verwendet keine dynamische Speicherzuordnung selbst. Intern verwendet libusb die dynamische Speicherzuweisung übermäßig. Der Kommunikationsfluss funktioniert wie erwartet. Gibt es eine spezielle Funktion, um einen internen dynamischen Speicher nach der Verwendung von libusb_interrupt_transfer freizugeben? Hat jemand eine Idee, was den kontinuierlichen Speicheranstieg während der Laufzeit verursacht?Speicherleck synchronen Lese-Interrupt-Übertragung Daten über libUSB

enter image description here

Mein Protokoll implementiert einen Zwei-Wege-Handshake. Aus diesem Grund verursacht ein einfacher Datenaustausch eine Übertragung von OUT (Anforderung), IN (Ack/Nack), IN (Antwort) und OUT (Ack/Nack). Die Berichtsgröße beträgt 32 Bytes, der outEndpointAddr ist 1, der inEndpointAddr ist 129, Hier sind die relevanten Code-Schnipsel.

int main (void) 
{ 
    uint32_t devFound = 0; 
    uint32_t devErrors = 0; 

    ... 

    int libUsbErr = 0; 
    if(!findSensor(&devFound, &devErrors, &libUsbErr, foundCB)) 
     printf("finding sensor failed %d\n", libUsbErr); 

    if(!openSensor(mySensor, &libUsbErr)) 
     printf("open sensor failed %d\n", libUsbErr); 

    int i = 0; 
    while(1) 
    { 
     printf("[%06d] Int Temp %f C\n",i++, readIntTemper()); 
     Delay(0.5); 
    } 
    closeSensor(&mySensor, NULL); 

    closeSensorContext(); 
    return 0; 
} 

float readIntTemper() 
{ 
    static uint8_t tmp[32]; 
    static uint8_t response[32]; 

    ...//Prepare request frame 

    int libUsbErr = 0; 
    if(!HID_Write(mySensor, tmp, &written, 4000, &libUsbErr)) 
    { 
     printf("write request failed %d\n", libUsbErr); 
     return 0; 
    } 

    //Read Ack/Nack 
    if(!HID_Read(mySensor, tmp, &read, 4000, &libUsbErr)) 
    { 
     printf("Read ACK NACK failed %d\n", libUsbErr); 
     return 0; 
    } 

    ...//Test if Ack/Nack 


    if(!HID_Read(mySensor, response, &read, 4000, &libUsbErr)) 
    { 
     printf("Read response failed %d\n", libUsbErr); 
     return 0; 
    }    

    ... //Prepare ACK 

    if(!HID_Write(mySensor, tmp, &written, 4000, &libUsbErr)) 
    { 
     printf("Ack response failed %d\n", libUsbErr); 
     return 0; 
    } 

    ... 

    float* temper = (float*)&response[8]; 
    return *temper; 
} 

bool HID_Write(const Sensor* sens, uint8_t* repBuf, int* transferred, uint32_t timeout, int* libUsbErr) 
{ 
    if(sens == NULL || repBuf == NULL || transferred == NULL) 
     return returnlibUSBErr(libUsbErr, -1008); ///TODO nice error codes; 

    if(!sens->claimed) 
     return returnlibUSBErr(libUsbErr, -1012); ///TODO nice error codes; 

    int r = libusb_interrupt_transfer(sens->devHandle, sens->outEndpointAddr, 
          repBuf, sens->outRepSize, transferred, timeout); 
    if (r < 0) 
     return returnlibUSBErr(libUsbErr, r); 
    return returnlibUSBErr(libUsbErr, LIB_USB_OK); 
} 

bool HID_Read(const Sensor* sens, uint8_t* repBuf, int* read, uint32_t timeout, int* libUsbErr)    
{  
    if(sens == NULL || read == NULL) 
     return returnlibUSBErr(libUsbErr, -1008); ///TODO nice error codes; 

    if(!sens->claimed) 
     return returnlibUSBErr(libUsbErr, -1012); ///TODO nice error codes;  

    int r = libusb_interrupt_transfer(sens->devHandle, sens->inEndpointAddr, repBuf,sens->inRepSize, read, timeout); 
    if (r < 0) 
     return returnlibUSBErr(libUsbErr, r); 
    return returnlibUSBErr(libUsbErr, LIB_USB_OK); 
} 

EDIT

Wenn diese Anweisung gefolgt Speichernutzung zu überwachen:

https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/using-performance-monitor-to-find-a-user-mode-memory-leak

das Leck zu finden habe ich UMDH Windows-Tool wie hier erwähnt:

https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/using-umdh-to-find-a-user-mode-memory-leak

Das Problem ist, dass ich CVI NI-Kompilierer verwenden muss, um meine Anwendung zu erstellen. Ich konnte die Symboltabelle nicht aus diesem Compiler holen. Mein Heap Dump Diff zeigt also nur Adressen an.

// Each log entry has the following syntax:         
//                   
// + BYTES_DELTA (NEW_BYTES - OLD_BYTES) NEW_COUNT allocs BackTrace TRACEID 
// + COUNT_DELTA (NEW_COUNT - OLD_COUNT) BackTrace TRACEID allocations  
//  ... stack trace ...             
//                   
// where:                 
//                   
//  BYTES_DELTA - increase in bytes between before and after log   
//  NEW_BYTES - bytes in after log          
//  OLD_BYTES - bytes in before log          
//  COUNT_DELTA - increase in allocations between before and after log 
//  NEW_COUNT - number of allocations in after log      
//  OLD_COUNT - number of allocations in before log      
//  TRACEID - decimal index of the stack trace in the trace database  
//   (can be used to search for allocation instances in the original 
//   UMDH logs).              
//                   


+ 80000 (80000 -  0)  1 allocs BackTrace4920B3C 
+  1 ( 1 -  0) BackTrace4920B3C allocations 

    ntdll!RtlAllocateHeap+274 
    cvirte!LoadExternalModule+291EC 
    cvirte!CVIDynamicMemoryInfo+12B6 
    cvirte!CVIDynamicMemoryInfo+1528 
    cvirte!CVIDynamicMemoryInfo+1AF9 
    cvirte!mblen+84D 
    cvirte!_CVI_Resource_Acquire+116 
    cvirte!malloc+68 
    libUSB_HID!???+0 : 41DCE8 
    libUSB_HID!???+0 : 4E95C7 
    libUSB_HID!???+0 : 4C13BE 
    libUSB_HID!???+0 : 4BA09D 
    libUSB_HID!???+0 : 4C7ABA 
    libUSB_HID!???+0 : 4F92F0 
    libUSB_HID!???+0 : 4FB3BD 
    libUSB_HID!???+0 : 4FC50E 
    libUSB_HID!???+0 : 415C31 
    libUSB_HID!???+0 : 408847 
    libUSB_HID!???+0 : 402967 
    libUSB_HID!???+0 : 41B51E 
    libUSB_HID!???+0 : 41A021 
    kernel32!BaseThreadInitThunk+E 
    ntdll!__RtlUserThreadStart+70 

I ersetzt auch alle frei, alloc, calloc und realloc cmds innerhalb LibUSB mit meinem eine eigene Implementierung Anfrage jeden einzelnen Speicher-Tracking. Diese Verfolgung zeigt kein Speicherleck. Die Menge der zugewiesenen Bytes bleibt zur Laufzeit wie erwartet konstant. Wie auch immer, die UMDH-Tools zeigen eine Heap-Allokationsdifferenz. Ich habe also keine Ideen, was ich als nächstes testen soll.

+1

Ist es C oder C++? Löschen Sie unpassende Tags. – tilz0R

+0

Und was ist deine Frage? Kannst du [mcve] und [ask] lesen? – Stargateur

+0

Ich habe das unpassende Tag entfernt.Fragen: Gibt es eine spezielle Funktion, um einen internen dynamischen Speicher nach der Verwendung von libusb_interrupt_transfer freizugeben? Hat jemand eine Idee, was den kontinuierlichen Speicheranstieg während der Laufzeit verursacht? –

Antwort

0

Sorry Leute, ich portierte mein Programm auf minGW gcc und alles funktioniert wie erwartet. Es scheint, dass meine Portierung von libusb für den CVI-Compiler nicht vollständig korrekt ist. Jetzt benutze ich die Standard-DLL und das Speicherleck ist weg.

1

Mein einfaches Benutzerprogramm verwendet keine dynamische Speicherzuweisung.

Leider tun diese libusb_xxx_transfer Funktionen Sachen mit malloc() intern. Aber es wird auch angenommen, dass die entsprechende free() kurz vor dem Verlassen des Aufrufers zu tun.

Dieser Speicher wird normalerweise nicht an das Betriebssystem zurückgegeben, sondern in der Anwendung für die nächsten malloc() Aufrufe beibehalten. Als Ergebnis sehen Sie etwas Speicherverbrauch im Aufgabenmanager.

Deshalb brauchen Sie bessere Tools zum Erkennen von tatsächlichen Speicherlecks, wie Valgrind.