+ -
当前位置:首页 → 问答吧 → 奇怪的malloc()!

奇怪的malloc()!

时间:2010-08-23

来源:互联网

本帖最后由 zhuqing_739 于 2010-08-23 15:30 编辑

众所周知,malloc()是在堆空间分配内存的,麻烦大家来看一段代码:
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>

  4. typedef struct student
  5. {
  6.         char name[11];
  7.         float score;
  8.         struct student *node;

  9. }STUDENT;

  10. int main(int argc, char *argv[])
  11. {
  12.        
  13.                STUDENT *p1, *p2, *p3;

  14.         printf("the size of STUDENT is %d\n",sizeof(STUDENT));

  15.         p1 = (STUDENT *)malloc(sizeof(STUDENT));
  16.         if (NULL == p1)
  17.         {
  18.                 printf("malloc error");
  19.                 return 1;
  20.         }
  21.                 printf("the address is %p\n",p1);

  22.         p2 = (STUDENT *)malloc(sizeof(STUDENT));
  23.         if (NULL == p2)
  24.         {
  25.                 printf("malloc error");
  26.                 return 1;
  27.         }
  28.         printf("the address is %p\n",p2);

  29.         p3 = (STUDENT *)malloc(sizeof(STUDENT));
  30.         if (NULL == p3)
  31.         {
  32.                 printf("malloc error");
  33.                 return 1;
  34.         }
  35.                 printf("the address is %p\n",p3);

  36.         free(p1);
  37.         p1 = NULL;
  38.         free(p2);
  39.         p2= NULL;
  40.         free(p3);
  41.         p3 = NULL;
  42.        
  43.    
  44.         return 0;
  45. }
复制代码
再来看一下输出结果:

the size of STUDENT is 20
the address is 0x804a008
the address is 0x804a020
the address is 0x804a038

请问:很明显,既然STUDENT的大小为20个字节,那为什么malloc()分配的空间会是24(0x804a020 - 0x804a008 = 0x804a038 - 0x804a020 = 24)个字节呢?
ps: 上述程序是在Linux下运行的!
谢谢!

作者: zhuqing_739   发布时间: 2010-08-23

分配的内存地址会对齐,很可能多给些

作者: hellioncu   发布时间: 2010-08-23

20个字节,20已经是4的倍数了,已经对齐了啊!?

作者: zhuqing_739   发布时间: 2010-08-23

本帖最后由 zhangsuozhu 于 2010-08-23 15:36 编辑

我猜有二种可能。一种是malloc分配时是4K分页对齐的。第二种可能malloc在分配内存时加了些自已的信息在里面。

同楼主求甚解!

作者: zhangsuozhu   发布时间: 2010-08-23

难道多出来的4个字节就是传说中的“内存碎片”吗?

作者: zhuqing_739   发布时间: 2010-08-23



QUOTE:
20个字节,20已经是4的倍数了,已经对齐了啊!?
zhuqing_739 发表于 2010-08-23 15:29




    可能是按8字节对齐的

作者: hellioncu   发布时间: 2010-08-23



QUOTE:
可能是按8字节对齐的
hellioncu 发表于 2010-08-23 15:38




    不对啊!如果是按8个字节对齐的话,第一个printf()输出结果就不是20了!

作者: zhuqing_739   发布时间: 2010-08-23



QUOTE:
不对啊!如果是按8个字节对齐的话,第一个printf()输出结果就不是20了!
zhuqing_739 发表于 2010-08-23 15:42




    不是说你的结构,是说malloc分配的内存地址

作者: hellioncu   发布时间: 2010-08-23

SGI的malloc自己也需要保存一些信息在内存里面。应该是这些信息占用了空间,我看看malloc源码

作者: davelv   发布时间: 2010-08-23

本帖最后由 zhuqing_739 于 2010-08-23 16:02 编辑


QUOTE:
不是说你的结构,是说malloc分配的内存地址
hellioncu 发表于 2010-08-23 15:44




    看下面这段改过的程序就知道不是按8对齐的了!
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>

  4. typedef struct student
  5. {
  6.         char name[11];
  7.         float score;
  8.         struct student *node;

  9. }STUDENT;

  10. int main(int argc, char *argv[])
  11. {
  12.        
  13.     STUDENT *p1, *p2, *p3;

  14.         printf("the size of STUDENT is %d\n",sizeof(STUDENT));

  15.         p1 = (STUDENT *)malloc([size=5]4[/size]);
  16.         if (NULL == p1)
  17.         {
  18.                 printf("malloc error");
  19.                 return 1;
  20.         }
  21.     printf("the address is %p\n",p1);

  22.         p2 = (STUDENT *)malloc([size=5]4[/size]);
  23.         if (NULL == p2)
  24.         {
  25.                 printf("malloc error");
  26.                 return 1;
  27.         }
  28.         printf("the address is %p\n",p2);

  29.         p3 = (STUDENT *)malloc([size=5]4[/size]);
  30.         if (NULL == p3)
  31.         {
  32.                 printf("malloc error");
  33.                 return 1;
  34.         }
  35.     printf("the address is %p\n",p3);

  36.         free(p1);
  37.         p1 = NULL;
  38.         free(p2);
  39.         p2 = NULL;
  40.         free(p3);
  41.         p3 = NULL;
  42.        
  43.    
  44.         return 0;
  45. }
复制代码
看一下输出结果:
the size of STUDENT is 20
the address is 0x804a008
the address is 0x804a018
the address is 0x804a028

作者: zhuqing_739   发布时间: 2010-08-23

看了一下大源代码。有如下注释:


QUOTE:
    Convert request size to internal form by adding SIZE_SZ bytes
    overhead plus possibly more to obtain necessary alignment and/or
    to obtain a size of at least MINSIZE, the smallest allocatable
    size. Also, checked_request2size traps (returning 0) request sizes
    that are so large that they wrap around zero when padded and
    aligned.

作者: zhangsuozhu   发布时间: 2010-08-23

另外:请问谁有C库函数的源代码啊?
我一直想看一下,各个库函数是怎么编写的,在网上就是找不到!如果有,发到我的邮箱:
[email protected]
或者:
MSN:[email protected]
小弟谢谢了!

作者: zhuqing_739   发布时间: 2010-08-23

回复 zhuqing_739


    http://www.gnu.org/software/libc/

作者: zhangsuozhu   发布时间: 2010-08-23

楼主发了一系列“奇怪的……”文章

作者: jnjn999   发布时间: 2010-08-23

这样,就有人进来了!

作者: zhuqing_739   发布时间: 2010-08-23

讲最小分配大小的时候有这么一段话
  Minimum overhead per allocated chunk:   4 or 8 bytes
       Each malloced chunk has a hidden word of overhead holding size
       and status information.

  Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
                          8-byte ptrs:  24/32 bytes (including, 4/8 overhead)

       When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
       ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
       needed; 4 (8) for a trailing size field and 8 (16) bytes for
       free list pointers. Thus, the minimum allocatable size is
       16/24/32 bytes.

       Even a request for zero bytes (i.e., malloc(0)) returns a
       pointer to something of the minimum allocatable size.

另外附上内存空间图
  1.     An allocated chunk looks like this:


  2.     chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  3.             |             Size of previous chunk, if allocated            | |
  4.             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  5.             |             Size of chunk, in bytes                       |M|P|
  6.       mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  7.             |             User data starts here...                          .
  8.             .                                                               .
  9.             .             (malloc_usable_size() bytes)                      .
  10.             .                                                               |
  11. nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  12.             |             Size of chunk                                     |
  13.             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
复制代码
具体信息自己参考源码malloc.c

作者: davelv   发布时间: 2010-08-23

见编程珠玑中文第二版P70结尾处

作者: pk8995   发布时间: 2010-08-23

怎么查看malloc.c的源码啊?谢谢!

作者: zhuqing_739   发布时间: 2010-08-23

glibc各个版本的源码此处有下载
ftp://ftp.gnu.org/gnu/glibc/

作者: davelv   发布时间: 2010-08-23

看到了如下注释:原来内存块之间是有8字节对齐的(size_t==4)

Alignment:                              2 * sizeof(size_t) (default)
       (i.e., 8 byte alignment with 4byte size_t). This suffices for
       nearly all current machines and C compilers. However, you can
       define MALLOC_ALIGNMENT to be wider than this if necessary.

作者: davelv   发布时间: 2010-08-23

发的得到顶顶顶顶顶顶顶顶顶顶顶顶的

作者: 短   发布时间: 2010-09-17