【问题标题】:Why C standard library does not provide a function for knowing the size of allocated memory?为什么C标准库没有提供知道分配内存大小的功能?
【发布时间】:2020-05-02 18:03:40
【问题描述】:

当通过调用malloc()动态分配一些内存时,操作系统会以某种方式在内部存储分配的内存量(以跟踪使用的内存等),因此我们只提供指向free()的指针'不再需要那个内存块了。

但是,我们cannot 以可移植且独立于操作系统/编译器的方式检索只有指针的大小。存在一些不可移植的方式,例如 Windows/Visual C 上的 _msize 或 glibc 中的 malloc_usable_size。因此,唯一的方法仍然是传播所有需要的大小以及相应的指针等,这很容易出错。

那么,问题是:为什么 C 标准开发人员决定不在标准中包含可移植函数?

附:问“为什么”可能是不恰当的,因为它通常至少在某种程度上涉及基于意见的事情,但在这里我相信这样做是有一些根本原因的。

【问题讨论】:

    标签: c memory memory-management malloc size


    【解决方案1】:

    没有技术问题阻止 C 标准委员会添加一个新的库函数来检索通过 malloc()calloc()realloc()aligned_alloc()、@ 先前返回的有效指针可访问的字节数987654325@ 或任何类似功能。返回的数字不一定是最初传递给分配函数的大小,可以想象这个信息可能根本不可用,所以返回值0 表示该信息不可用。

    尚未添加此类功能的原因可能是 C 标准委员会通常非常不愿意添加新功能。例如,strdup() 花了 30 多年的时间才最终进入 C 标准(它将成为下一个版本的一部分),尽管几十年来大多数 C 库中都提供了一致的实现。

    对于之前没有由内存分配函数返回或已释放的任何指针,此函数将具有未定义的行为,就像freerealloc。是否为NULL 定义是有争议的,但在这种情况下,0 的返回值似乎是合适的。如果大小未知,这对于不存储此信息的虚拟分配器是可能的,返回值0 也将指示这种情况。

    这是来自 GNU lib C 中 malloc_usable_size 手册页的摘要:

    姓名

    malloc_usable_size - 获取从堆分配的内存块的大小

    概要

       #include <malloc.h>
        
       size_t malloc_usable_size(void *ptr);
    

    描述

    malloc_usable_size() 函数返回ptr 指向的块中的可用字节数、指向malloc(3) 分配的内存块的指针或相关函数。

    返回值

    malloc_usable_size() 返回ptr 指向的已分配内存块中的可用字节数。如果ptrNULL,则返回0

    属性

    多线程(参见pthreads(7)):malloc_usable_size() 函数是线程安全的。

    符合

    这个函数是一个 GNU 扩展。

    注意事项

    由于对齐和最小大小限制,malloc_usable_size() 返回的值可能大于请求的分配大小。尽管应用程序可以覆盖多余的字节而不会产生不良影响,但这不是好的编程习惯:分配中多余的字节数取决于底层实现。

    这个函数的主要用途是调试和自省。

    另请参阅

    malloc(3)

    【讨论】:

    • .. 返回的值也可能不为零且不正确。如果另一个线程在“allocsize”函数返回时释放或重新分配块......
    • @MartinJames:当然,对共享变量的任何不受保护的并发访问都会调用未定义的行为。仅仅取消引用另一个线程可以同时释放的指针也有未定义的行为。
    • “偏移”指针的行为是否为malloc_usable_size 明确定义? IE。 char *x = malloc(N); x += 8。在我的简单测试中,它返回了0(未知?)。这是有保证的行为吗?我想用它来检查指针是否指向分配的开始(如 malloc 返回的那样)。
    • @DanM.: 一点也不:malloc_usable_size 对于任何非空指针没有由分配函数返回或已释放的行为未定义。如果添加偏移量来实现标记指针,则必须从传递给此函数的标记指针以及free()realloc() 中删除此偏移量。假设分配的指针是 16 字节对齐的并且您使用 4 位标记,您应该编写 malloc_usable_size((void *)((uintptr_t)(x) &amp; ~15)) 来获取实际的对象指针。超过 15 的偏移量,没有可靠的方法来计算 malloc() 返回的原始指针。
    • @DanM.:如果您自己使用mmap 映射内存,则可以通过测试其低12 位来检测指针x 是否指向页面的开头,具体取决于系统页面大小,但同样,这不是超过 4095 的偏移量的通用解决方案。
    【解决方案2】:

    因为您可以获得指向未从malloc 和朋友返回的内容的指针。

    int x = 10;
    int * p = &x;
    

    您正在谈论的函数必须确定p 是否从malloc 返回(可能很昂贵)。如果不是(在这种情况下),它就无法知道分配的空间量。如果你有一个指向 malloc 分配的指针,而不是 malloc 分配的确切指针,你也会遇到问题。

    int * p = malloc(sizeof(int) * 10);
    int * p2 = p + 5;
    

    如果我询问p2 的大小,正确的结果是什么?

    更一致的方法是在需要的地方传递尺寸。这使您可以处理地址,无论它们来自何处,包括某些内存块的偏移量(例如,数组,就像我在上面使用 p2 所做的那样)。

    【讨论】:

    • 我不同意第一段,如果这是原因,我认为free 不存在,C 没有保护性 API(保护性是正确的词吗?)
    • @DavidRanieri,确实,像 OP 所询问的函数可能带有与 free 相同的限制,即参数必须是分配函数返回的指针,并且随后不会被释放。但那又怎样?为了适应 Stephen 提到的指针的使用,大多数代码都需要在假设不能使用假设的 size 函数的情况下编写,因此提供这样的函数几乎没有用处。释放是一个完全不同的用例。
    • @JohnBollinger,是的,它很容易出错,但是在指针方面有什么不容易出错的吗?无需进一步说明:使用不正确的类型取消引用 void *,这是编译器无法控制的,甚至不会发出警告,但 void * 很有用。
    • @DavidRanieri,问题不在于神奇的内存大小函数容易出错。这是它在大多数情况下不适合,而对于几乎所有其他情况不必要。同样,可以提供这样的功能,具有与free 相同的限制,但它基本上不会被使用,正如问题中提供的特定于实现的示例一样。请记住,这在任何情况下都不是可行性问题,而是事后对负责编写和维护标准的人员的决策过程进行猜测。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-11
    • 2013-10-30
    • 1970-01-01
    • 2011-03-07
    • 2017-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多