为什么malloc分配的字节数与请求的数不同?

问题描述 投票:7回答:12

我有这段代码

#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个额外的字节。

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

编辑:我见过How can I get the size of an array from a pointer in 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的帖子。我错了吗?

c debugging gcc malloc
12个回答
9
投票

你有一个bug。代替:

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

你应该有

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

请注意代码中缺少的指针。我怀疑这是你观察到的行为源于何处。


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


1
投票

在指针站成以下数组的大小之前,这是一个32/64位整数(不知道是否有符号或无符号)


1
投票

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

虽然它在不同平台上有所不同。在我的X86系统上,malloc()分配17字节的min,即使我正在请求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;
}

0
投票

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

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


31
投票

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

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

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

不要假设malloc正在做什么,而不是文档所说的!


17
投票

malloc函数总是分配比您要求的更多,以便存储一些簿记信息。毕竟,当你打电话给free()时,它需要知道这个块有多大。

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

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

另一方面,malloc总是分配给定数量的字节,无论你将结果投射到后来。试试这个:

    array=(short int*)malloc(sizeof(short int) * size);

12
投票

无法保证两个malloc调用返回完全打包在一起的块 - 实际上根本没有任何关于结果的保证,除非它是非NULL,它将指向一个与请求的块一样大的块。

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

一些分配器(例如,在窗口上)提供了一个库函数来发现给定指针的块大小,但是,有些不这样做,因为它是一个相当深奥的特性。


5
投票

malloc返回的内容取决于malloc的实现和体系结构。正如其他人已经说过的那样,您可以保证达到所需的内存量,或者为NULL。这也是为什么有时你可以写一个数组的末尾,而不是一个分段错误。这是因为你实际上有权访问这个内存,你只是不知道它。


4
投票

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

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


3
投票

malloc()将拥有自己的开销。

更不用说,无法保证连续2次分配将始终相邻。


2
投票

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


2
投票

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

分配

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

需要=要求+ 8

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

如果需要> 16,则bucket =(log(required)/ 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

© www.soinside.com 2019 - 2024. All rights reserved.