【问题标题】:Memory leak synchronous reading interrupt transfer data via libUSB内存泄漏同步读取中断通过libUSB传输数据
【发布时间】:2017-11-07 09:38:12
【问题描述】:

我发现内存泄漏通过 USB 中断传输同步使用 libUSB 读取数据。我的简单用户程序本身不使用任何动态内存分配。在内部,libusb 过度使用了动态内存分配。通信流程按预期工作。使用 libusb_interrupt_transfer 后是否有释放任何内部动态内存的特殊功能?有谁知道是什么原因导致运行时内存不断增加?

我的协议实现了双向握手。因此,简单的数据交换会导致 OUT(request)、IN(Ack/Nack)、IN(Response) 和 OUT(Ack/Nack) 传输。报告大小为32 Bytes,outEndpointAddr为1,inEndpointAddr为129,下面是相关代码sn-ps。

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);
}

编辑

如果按照此说明监控内存使用情况:

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

为了找到泄漏,我使用了这里提到的 UMDH Windows 工具:

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

问题是我必须使用 CVI NI 编译器来构建我的应用程序。我无法从这个编译器中得到符号表。所以我的堆转储差异只显示地址。

// 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

我还用我自己的实现来跟踪每个内存请求,替换了 libUSB 中的所有 free、alloc、calloc 和 realloc cmd。此跟踪未显示任何内存泄漏。分配的字节数在运行时按预期保持不变。无论如何,UMDH 工具显示了堆分配差异。所以我完全不知道下一个 atm 测试什么。

【问题讨论】:

  • 是 C 还是 C++?删除不适当的标签。
  • 你的问题是什么?你能读懂minimal reproducible exampleHow to Ask吗?
  • 我删除了不合适的标签。问题: 使用 libusb_interrupt_transfer 后是否有释放任何内部动态内存的特殊功能?有谁知道是什么原因导致运行时内存不断增加?
  • 你是如何测量内存使用的?
  • 通过windows任务管理器。

标签: c windows memory-leaks usb libusb


【解决方案1】:

我的简单用户程序没有使用任何动态内存分配。

不幸的是,那些libusb_xxx_transfer 函数在内部与malloc() 做一些事情。但也应该在退出调用者之前执行相应的free()

该内存通常不会返回给操作系统,而是保留在应用程序中以供下一次malloc() 调用使用。结果,您将在任务管理器中看到一些内存使用情况。

这就是为什么您需要更好的工具来检测实际内存泄漏,例如 valgrind。

【讨论】:

    【解决方案2】:

    对不起,我将我的程序移植到 minGW gcc 并且everythink 正在按预期工作。看来我为 CVI 编译器移植 libusb 并不完全正确。现在我使用标准 dll 并且内存泄漏消失了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-10
      • 1970-01-01
      • 2016-04-29
      • 1970-01-01
      相关资源
      最近更新 更多