10

我有这段代码

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

int main(){
    void *a, *b;

    a = malloc(16);
    b = malloc(16);
    printf("\n   block size (for a): %p-%p : %li", b, a, b-a);

    a = malloc(1024);
    b = malloc(1024);
    printf("\n   block size (for a): %p-%p : %li", b, a, b-a);  
}

这不应该打印最后分配的块大小(16 或 1024)吗?它改为打印 24 和 1032,因此分配的内存量似乎有 8 个额外字节。

我的问题是(在制作这个测试用例之前)我malloc()在一个函数(1024 字节)中执行,并返回分配的结果。当检查函数返回的块大小时,我得到 516 个块......我不明白为什么。我想这可能是对分配的缓冲区进行一些处理后发生内存损坏的原因:)

编辑:我已经看到如何从 C 中的指针获取数组的大小?似乎问同样的事情,抱歉重新发布。

我已将示例重做为更具体的代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

short int * mallocStuff(long int number, short int base){
    short int *array;
    int size=1024;

    array=(short int*)calloc(1,size);
    //array=(short int*)malloc(size);

    return array;
}

int main(){
    short int **translatedArray;

    translatedArray=malloc(4*sizeof(short int));

    int i;
    for(i=0;i<4;i++){
        translatedArray[i]=mallocStuff(0,0);

        if(i>0)
            printf("\n   block size (for a): %p-%p : %i",
                translatedArray[i], translatedArray[i-1], translatedArray[i]-translatedArray[i-1]);
    }

    return 0;
}

输出是

   block size (for a): 0x804a420-0x804a018 : 516
   block size (for a): 0x804a828-0x804a420 : 516
   block size (for a): 0x804ac30-0x804a828 : 516

根据上面的帖子大于1024。我错了吗?

4

12 回答 12

31

首先,Malloc 不保证两个连续的 malloc 调用返回连续的指针。

其次,根据您的具体架构,应用不同的对齐规则;有时您可能会要求一个字节,但该体系结构更喜欢以 8 或 4 字节为间隔进行分配。

第三, malloc 需要一些开销来存储分配的块有多大,等等。

不要假设 malloc 所做的事情超出了文档所说的内容!

于 2009-01-09T23:48:53.870 回答
18

malloc函数总是分配比你要求的多一点,以便存储一些簿记信息。毕竟,当你调用它时,free()它需要知道块有多大。

此外,通常malloc实现会将请求的大小四舍五入到下一个 8 或 16 的倍数或其他一些四舍五入的数字。

更新:您问题的真正答案在于您对short int类型的使用。在类型化指针之间进行指针算术(减法)时,C 和 C++ 返回指向的事物数量的差异。由于您指向short int大小为两个字节的 ,因此返回的值是您期望值的一半。

另一方面,malloc始终分配给定数量的bytes,无论您将结果转换为什么。试试这个:

    array=(short int*)malloc(sizeof(short int) * size);
于 2009-01-09T23:47:20.707 回答
12

不能保证两个 malloc 调用会返回完全打包在一起的块——事实上,根本无法保证结果,除非它不是 NULL,它将指向一个至少与请求的块一样大的块。

在内部,大多数 malloc 保存工作数据以帮助它们管理堆。例如,这 8 个字节可能包含两个指针——一个指向下一个块,一个指向前一个块。我不知道那 8 个字节是什么,因为您没有提到您正在运行哪个操作系统,但是 malloc 在幕后为自己使用一些内存是完全正常的。

一些分配器(例如在 Windows 上)提供了一个库函数来发现给定指针的块大小,但是,有些则没有,因为它是一个相当深奥的功能。

于 2009-01-09T23:49:53.757 回答
10

你有一个错误。代替:

translatedArray=malloc(4*sizeof(short int));

你应该有

translatedArray=malloc(4*sizeof(short int*));

请注意代码中缺少的指针。我怀疑这就是您观察到的行为的根源。


还要注意0x804a420 - 0x804a018 = 1032,不是516。该公式translatedArray[i] - translatedArray[i - 1]为您提供两个地址之间的元素数(短整数,或更简单地说,短整数),而不是字节数。

于 2009-01-10T00:04:29.750 回答
5

malloc 返回的内容取决于 malloc 的实现和架构。正如其他人已经说过的那样,您可以保证至少获得请求的内存量,即 NULL。这也是为什么有时,您可以写到数组的末尾,而不会出现分段错误。这是因为您实际上确实可以有效地访问此内存,只是您不知道而已。

于 2009-01-09T23:53:14.610 回答
4

malloc() 通常通过将可用堆拆分为各种大小的块来实现。在您的情况下, malloc() 返回 2 个连续的 1024(或 16)字节块。您提到的 8 字节空间由 malloc() 用于簿记信息。

请参阅 Doug Lea 的 malloc() impl 注释,以了解幕后发生的事情:http: //g.oswego.edu/dl/html/malloc.html

于 2009-01-10T00:04:14.573 回答
3

malloc()会有它自己的开销。

更不用说不能保证 2 个连续的分配从一开始就会彼此相邻。

于 2009-01-09T23:47:31.190 回答
2

如果返回 null 以外的任何内容,则为您的程序malloc分配的内存具有您传递给的大小。取两个差异调用的返回值之间的指针差异可以具有任何值,并且与第一个分配块的块大小无关(很少)。mallocmalloc

于 2009-01-09T23:49:46.567 回答
2

我找到了这个..并检查下面的链接以获取更多信息。

分配

通过首先将请求的字节转换为存储桶数组中的索引,从空闲池中分配一个块,使用以下等式:

需要 = 请求 + 8

如果需要 <= 16,则桶 = 0

如果需要 > 16,则 bucket = (log(needed)/log(2) 向下舍入到最接近的整数) - 3

桶所锚定的列表中每个块的大小为块大小 = 2 桶 + 4。如果桶中的列表为空,则使用 sbrk 子例程分配内存以将块添加到列表中。如果块大小小于页,则使用 sbrk 子例程分配页,并将块大小除以页大小得到的块数添加到列表中。如果块大小等于或大于一页,则使用 sbrk 子例程分配所需的内存,并将单个块添加到存储桶的空闲列表中。如果空闲列表不为空,则将列表头部的块返回给调用者。列表中的下一个块然后成为新的头。

http://publib.boulder.ibm.com/infocenter/systems/index.jsp?topic=/com.ibm.aix.genprogc/doc/genprogc/sys_mem_alloc.htm

于 2009-04-13T04:29:15.140 回答
1

指针前代表后面数组的大小,是一个32/64位整数(不知道有符号还是无符号)

于 2009-01-09T23:46:39.303 回答
1

所以分配的内存量似乎有 8 个额外的字节? malloc()您系统上的实现似乎分配了额外的字节来维护元数据信息,例如堆部分有多大,起始地址是什么等信息。

虽然它在不同的平台上有所不同。在我的 X86 系统malloc()17,即使我请求malloc(0).

int main(void) {
    int *p = malloc(0);
    if(p == NULL) {
        /* error handling */
    }
    printf("%d\n",p[-1]);/ *it prints 17 bytes */
    /* some code */
    return 0;
}
于 2015-09-20T08:21:00.017 回答
0

malloc() 可以分配连续的内存,但是当您调用 malloc() 2 次并且不能期望通过减去两个指针变量来分配的内存是连续的...

但是分配的内存是虚拟内存,它是内核实现的一部分,具体来说是内存管理(VFS)。它可能不会影响应用程序功能。

于 2018-02-16T10:09:19.690 回答