【问题标题】:Is there a way to know size of a pointer passed to a __free_hook in Linux?有没有办法知道在 Linux 中传递给 __free_hook 的指针的大小?
【发布时间】:2013-02-28 08:54:42
【问题描述】:

我想跟踪一个大型应用程序当前分配了多少内存。

我发现我可以在 malloc/free/realloc 周围安装钩子来拦截内存分配调用:

http://man7.org/linux/man-pages/man3/malloc_hook.3.html

所以我要跟踪的是分配的总字节数 - 释放的总字节数。

现在的问题是 free 只需要一个指针而不是一个大小。

In 可以在我的 malloc 挂钩中创建我自己的映射或哈希映射,以跟踪为该指针分配了多少内存,但这会导致相当多的开销。

有没有什么方法(即使它有点像 hack)在 Linux(64 位)上调用 free 时获得 ptr 的大小(使用默认的 g++ malloc)?

【问题讨论】:

  • 问题相似但不完全相同。该人打算使用它来确定数组在代码本身中的长度,建议在这些答案中避免使用。在这种情况下,这个问题只是为了跟踪总内存。
  • 也许 - 但在这两种情况下接受的答案是相同的......“使用 malloc_usable_size()”。这使它在我看来至少是一个“可能的重复”。通过创建链接,我们为偶然发现一个问题的人提供了查看更多可能答案的机会。

标签: c linux malloc hook free


【解决方案1】:

linux man malloc_usable_size

malloc_usable_size() 返回可用的字节数 动态分配的缓冲区 ptr,它可能大于 请求的大小(但保证至少一样大,如果 请求成功)。通常,您应该存储 请求分配大小而不是使用此函数。

【讨论】:

    【解决方案2】:

    这不是对您问题的直接回答,但如果您对分配的总内存感兴趣,那么解决方案如下:

    我想你会对它返回的结构的uordblks 字段最感兴趣。

    请注意,这不是标准的 POSIX 函数,但我想这就是您对像这样的非标准内省的期望......

    【讨论】:

      【解决方案3】:

      你需要在 malloc 中安装一个钩子来构建一个缓存请求块大小的指针表,然后当你释放时,在以前的 malloc 项数据库中搜索指针。

      这样您将知道要减少当前分配的堆总和多少(如果这是您的目标),并且将有一个方便的地方列出仍然保留在内存中的所有堆“区域”。

      【讨论】:

        【解决方案4】:

        内存块的大小通常存储在指针下方。虽然这是一个 hack(你说我可以......),但以下代码在我的 Linux 机器上运行:

        #include <stdio.h>
        #include <stdlib.h>
        
        int main(){
        int *p, n=123;
        p = (int*)malloc(n*sizeof(int));
        printf("allocated %d bytes for p\n", n*sizeof(int));
        printf("p[-2] : %d \n", *(p-2));
        printf("malloc_useable_size(p) : %d\n", malloc_usable_size(p));
        free(p);
        }
        

        它产生的输出是这样的:

        allocated 492 bytes to p
        p[-2] : 513
        malloc_useable_size(p): 504
        

        请注意,p[-2] 中的大小不完全是 492 - 由于内务管理和边界对齐等原因,会占用一些额外的空间。

        另请注意 - 这适用于 gcc 编译器;但是g++ 抱怨指针转换,并且我没有声明malloc_useable_size()。看到@fanl 的回答后,我出于好奇添加了该行。在看到@OliCharlesworth 的回答后,我也对mallinfo 的输出进行了一些尝试。

        你可以改变 n 的值,你会发现事情非常吻合——例如,如果你将 n(在我上面的代码中)从 100 步进到 119,不同感兴趣变量的值如下:

          n | p[-2] | usable | uordblks
        ----+-------+--------+---------
        100    417     408       416
        101    417     408       416
        102    417     408       416
        103    433     424       432
        104    433     424       432
        105    433     424       432
        106    433     424       432
        107    449     440       448
        108    449     440       448
        109    449     440       448 
        110    449     440       448
        111    465     456       464   
        112    465     456       464
        113    465     456       464
        114    465     456       464
        115    481     472       480
        116    481     472       480
        117    481     472       480
        118    481     472       480
        119    497     488       496 
        

        usablep[-2] 之间始终存在 9 的差异,p[-2]uordblks 之间始终存在 1 的差异。 p[-2] 方法的优势在于它可以准确地告诉您要求 的内容——this 指针的大小。其他电话实际上可能会告诉您您真正想要什么...

        PS 很有可能对于非常大的内存块,您需要查看位于*((long int*)(p)-1)long integer。这给了我一个很好的宏的灵感:

        #define PSIZE(a) (*((long int*)(a)-1))
        

        然后你可以找出任何指针的大小

        printf("my pointer size is %ld\n", PSIZE(myPointer));
        

        无需担心指针的类型。我确认这适用于不同类型的指针,以及大于 4G 的块。显然,您可以决定在宏中减去 1,以便该数字与 mallinfo() 完全一致。

        编辑:在this earlier question 的答案之一中给出了对指针下方存储内容的更完整描述。这表明我观察到的“+1”实际上是由于存储在 LSB 中的标志。正确的方法是将结果与 ~3 相加,清除两个 LSB,然后从结果中减去 (long int*) 的大小(实际上原始答案减去 2*sizeof(unsigned long int) 但我认为那是错误):

        #define PSIZE(a) ((*((long int*)(a)-1))&~3 - sizeof(long int*))
        

        链接的答案强烈建议仅将其用于调试,而不是依赖于实际代码。我觉得不得不重复那个警告。

        【讨论】:

        • 这在很大程度上取决于 glibc 的 malloc du jour 是如何做事的……最好选择 @fanl 的答案。
        猜你喜欢
        • 2020-05-13
        • 2020-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多