2014-09-01 56 views
2

我想写一些单元测试,检查内存是否已被释放 - 检查内存泄漏 - 在OS X(10.9小牛)上。我试图使用mstats()和malloc_zone_statistics()来发现我需要的信息。但似乎他们不显示内存被释放(见下面的示例输出...内存使用免费后不会改变()被调用)为什么mstats和malloc_zone_statistics在空闲后不显示恢复的内存?

我怀疑这比具有更多的是与堆管理这些功能的问题。我认为这堆并不释放释放的内存,也许它可以在没有删除和添加块的开销的情况下重用它。

  1. 有没有办法告诉堆释放释放块?要更积极或关闭优化?
  2. 我只是不正确地使用mstats()或malloc_zone_statistics()?

更新:溶液中发现的......在底部提供...

这里是我的测试程序的输出:

=== Initial conditions === 
in use: 23584, allocated: 9437184, blocks: 320 
SimpleLeaker(19583,0x7fff7b2a2310) malloc: total: 9437184, used: 23584, free: 9413600 
=== Before allocation === 
in use: 23584, allocated: 9437184, blocks: 320 
SimpleLeaker(19583,0x7fff7b2a2310) malloc: total: 9437184, used: 23584, free: 9413600 
=== After malloc === 
in use: 33824, allocated: 9437184, blocks: 321 
SimpleLeaker(19583,0x7fff7b2a2310) malloc: total: 9437184, used: 33824, free: 9403360 
=== After free === 
in use: 33824, allocated: 9437184, blocks: 321 
SimpleLeaker(19583,0x7fff7b2a2310) malloc: total: 9437184, used: 33824, free: 9403360 

这里是为C代码程序:

#include <stdio.h> 
    #include <unistd.h> 
    #include <stdlib.h> 
    #include <pthread.h> 
    #include <mach/mach.h> 
    #include <mach/task.h> 
    #include <malloc/malloc.h> 
    #include <errno.h> 


    /** heapStats() 
    * print the output from the mstats() function: total heap bytes, 
    * used bytes, and free bytes. 
    */ 
    void heapStats() 
    { 
     struct mstats ms = mstats(); 
     malloc_printf(
     "total: %d, used: %d, free: %d\n", 
     ms.bytes_total, 
     ms.bytes_used, 
     ms.bytes_free); 
    } 

    /* heapInUse() 
    * Gather the heap usage metrics from each zone, using 
    * malloc_zone_statistics(). 
    */ 
    void heapInUse(
     size_t * bytesInUse, 
     size_t * blocksInUse, 
     size_t * sizeAllocated) 
    { 
     *bytesInUse = 0; 
     *blocksInUse = 0; 
     *sizeAllocated = 0; 
     unsigned int i; 
     vm_address_t * zones; 
     unsigned int count; 
     kern_return_t rc = 
     malloc_get_all_zones(mach_task_self(), 0, &zones, &count); 
     if (0 != rc) 
     { 
     fprintf(stderr, "rc was %d\n", rc); 
     } 
     for (i = 0; i < count; ++i) 
     { 
     malloc_zone_t * zone = (malloc_zone_t*)zones[i]; 
     char const * name = malloc_get_zone_name(zone); 
     if (NULL == name) 
     { 
      continue; 
     } 
     malloc_statistics_t stats; 
     stats.blocks_in_use = 0; 
     stats.size_in_use = 0; 
     stats.max_size_in_use = 0; 
     stats.size_allocated = 0; 
     malloc_zone_statistics(zone, &stats); 
     *bytesInUse += stats.size_in_use; 
     *blocksInUse += stats.blocks_in_use; 
     *sizeAllocated += stats.size_allocated; 
     } 
    } 

    /** main() 
    * entry point 
    */ 
    int main(int argc, const char * argv[]) 
    { 
     char * buff = (char *)0; 
     size_t bytesInUse = 0; 
     size_t blocksInUse = 0; 
     size_t sizeAllocated = 0; 
     printf("=== Initial conditions ===\n"); 
     heapInUse(&bytesInUse, &blocksInUse, &sizeAllocated); 
     printf(
     "in use: %zu, allocated: %zu, blocks: %zu\n", 
     bytesInUse, sizeAllocated, blocksInUse); 
     heapStats(); 

     printf("=== Before allocation ===\n"); 
     heapInUse(&bytesInUse, &blocksInUse, &sizeAllocated); 
     printf(
     "in use: %zu, allocated: %zu, blocks: %zu\n", 
     bytesInUse, sizeAllocated, blocksInUse); 
     heapStats(); 

     // Allocate the buffer 
     // 
     buff = (char *)malloc(10000); 
     printf("=== After malloc ===\n"); 
     heapInUse(&bytesInUse, &blocksInUse, &sizeAllocated); 
     printf(
     "in use: %zu, allocated: %zu, blocks: %zu\n", 
     bytesInUse, sizeAllocated, blocksInUse); 
     heapStats(); 

     // Free the buffer 
     // 
     if (NULL != buff) 
     { 
     free(buff); 
     buff = NULL; 
     } 
     printf("=== After free ===\n"); 
     heapInUse(&bytesInUse, &blocksInUse, &sizeAllocated); 
     printf(
     "in use: %zu, allocated: %zu, blocks: %zu\n", 
     bytesInUse, sizeAllocated, blocksInUse); 
     heapStats(); 

     // Get out 
     // 
     return 0; 
    } 

解决方案:感谢ŧ Ø从John Zwinck响应我接过仔细看看malloc/malloc.h,发现了一个方法malloc_zone_pressure_relief(),我可以使用强制堆释放未使用的字节,这样我可以得到准确的指标。

所以我加入这个方法:

void freeAsMuchAsPossible() 
{ 
    vm_address_t * zones; 
    unsigned int count; 
    unsigned int i; 

    kern_return_t rc = 
    malloc_get_all_zones(mach_task_self(), 0, &zones, &count); 
    if (0 != rc) 
    { 
    fprintf(stderr, "rc was %d\n", rc); 
    } 
    for (i = 0; i < count; ++i) 
    { 
    malloc_zone_t * zone = (malloc_zone_t*)zones[i]; 
    char const * name = malloc_get_zone_name(zone); 
    if (NULL == name) 
    { 
     continue; 
    } 
    malloc_zone_pressure_relief(zone, 0); 
    } 
} 

,并把它称为每次调用之前heapInUse(),像这样:

printf("=== Before allocation ===\n"); 
freeAsMuchAsPossible(); 
heapInUse(&bytesInUse, &blocksInUse, &sizeAllocated); 
printf(
    "in use: %zu, allocated: %zu, blocks: %zu\n", 
    bytesInUse, sizeAllocated, blocksInUse); 
heapStats(); 

现在我得到预期的和有用的结果,例如:

=== Initial conditions === 
in use: 23584, allocated: 9437184, blocks: 4294966976 
SimpleLeaker(22142,0x7fff7b2a2310) malloc: total: 9437184, used: 23584, free: 9413600 
=== Before allocation === 
in use: 23584, allocated: 9437184, blocks: 4294966976 
SimpleLeaker(22142,0x7fff7b2a2310) malloc: total: 9437184, used: 23584, free: 9413600 
=== After malloc === 
in use: 33824, allocated: 9437184, blocks: 4294966967 
SimpleLeaker(22142,0x7fff7b2a2310) malloc: total: 9437184, used: 33824, free: 9403360 
=== After free === 
in use: 23584, allocated: 9437184, blocks: 4294966966 
SimpleLeaker(22142,0x7fff7b2a2310) malloc: total: 9437184, used: 23584, free: 9413600 

利用这种技术,我可以编写单元测试,检查内存泄漏。非常好。

回答

2

在OS X上,由于10.7,我们可以使用malloc_zone_pressure_relief()迫使堆释放未使用的字节。我已经用解决方案更新了我的问题。

感谢John Zwinck对我的另一个细看malloc.h的反应,我发现了这个方法。

1

你可能是正确的:分配是每次调用空闲时间()不释放内存返回给操作系统。但是你可以使用mallopt()来改变它。尝试将M_MMAP_THRESHOLD设置为0.这将使每个分配独立。您可能不希望用于生产,但为了测试它可能会对您有所帮助。

+1

'mallopt()'似乎是一个聪明的事情,并且将是在Linux系统上追求的一个很好的途径。但是我正在使用OS X,'mallopt()'不可用,也许是因为转向了Clang。然而,这些建议让我更加关注malloc.h,并且我发现了一个函数'malloc_zone_pressure_relief()',它似乎强制堆释放未使用的字节。所以,谢谢你的推动。 – 2014-09-02 22:39:11

0

我会建议寻找到OSX leaks工具来查找内存泄漏的程序。介绍性文章可以在这里找到:leaks documentation at Mac Developer Library。您可以通过man leaks了解更多详情。另外,仅针对您的问题1,您可以使用libgmalloc。请man libgmalloc了解更多信息。另外,这些手册页包含指向其他工具的链接,例如malloc_history,您可能也会发现对于您的目的有用和/或更快。

+0

我想创建单元测试,发现内存泄漏,所以'泄漏'工具不会帮助我。但是当我需要排除通过自动化测试的泄漏问题时,知道它是可用的是很好的。我可以想象'malloc_history'也可能有用的情况。 – 2014-09-02 22:59:39

相关问题