请教:malloc(8)之后,系统到底给分配多少内存?

gxlzlu 2009-10-10 12:43:31
我们的习惯都是malloc(8)或者malloc(16).......
即分配内存都是用2的幂次方来分配。
我们可用的内存为8、16个字节,但是,根据系统的需要,会在每一段内存前面添加一些信息(如这段内存的长度等)
所以,系统实际分配出来的内存应该大于我们所申请的大小。
照此理解,malloc(128)之后,系统实际分配的内存有可能就是256个字节???
如果以上理解正确,那么以前的受到的“节约”的内存申请方法(用2的幂次方)岂不是最大的浪费内存的方法??
希望高人指点一下,谢谢!!
...全文
1366 46 打赏 收藏 转发到动态 举报
写回复
用AI写文章
46 条回复
切换为时间正序
请发表友善的回复…
发表回复
CandPointer 2011-05-28
  • 打赏
  • 举报
回复
[Quote=引用 45 楼 candpointer 的回复:]

去看看 内存管理的吧,


PhkMalloc, NetBSD采用的

Doug lea 的 dlmalloc , 空闲块用双链表组织


knuth 的 art of computer programing 里面,也有描述 动态存储分配的算法。
[/Quote]


找了个 dlmalloc 的
http://www.linuxeden.com/html/develop/20090523/65799.html
看了,就会豁然开朗。

当然,动态内存管理,还有很多种。。。

还有, Intel 的TBB, 分布式内存管理
手头有本 周伟明的 《多核计算与程序设计》 里面也有一些分布式内存管理
CandPointer 2011-05-28
  • 打赏
  • 举报
回复
去看看 内存管理的吧,


PhkMalloc, NetBSD采用的

Doug lea 的 dlmalloc , 空闲块用双链表组织


knuth 的 art of computer programing 里面,也有描述 动态存储分配的算法。
brauceunix 2011-05-28
  • 打赏
  • 举报
回复
char *line = NULL;
char *data = NULL;
char *buf = NULL;
int len = 0;
data = (char *)malloc(1400);
if (data == NULL) {
printf("data is NULL!\n");
}
line = (char *)malloc(204800);
if (line == NULL) {
printf("line is NULL!\n");
}
len = line-data;
printf("data:line-data is %d ", len);
buf = (char *)malloc(1000);
if (buf == NULL) {
printf("buf is NULL!\n");
}
printf("buf: buf-line is %d", buf-line);


分析结果:
data:line-data is 1408 buf: buf-line is 20488

PS: 项目中的代码,从各个文件中截取出来的。基于ubuntu..8.04..
brauceunix 2011-05-28
  • 打赏
  • 举报
回复
不错。。。。
leijydl 2010-09-23
  • 打赏
  • 举报
回复
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
main()
{
int *p1=malloc(16);
int *p2=malloc(16);
int *p3=malloc(24);
int *p4=malloc(24);
printf("%p\n",p1);
printf("%p\n",p2);
printf("%p\n",p3);
printf("%p\n",p4);

}
我用vi编译
结果如下:


0x84d8008
0x84d8020
0x84d8038
0x84d8058
pang123hui 2009-10-14
  • 打赏
  • 举报
回复
留名,学习一下
pcboyxhy 2009-10-14
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 gxlzlu 的回复:]
说到底,就是现在的操作系统已经不需要按照2的幂次方来分配内存了。
哦耶!!!
[/Quote]

是的,即使操作系统不为你优化,C的运行库还是会做这个事情。

但是也不能完全依赖实现,在写操作系统的时候,或者其它没有环境支持的时候,还是要考虑这个问题的
pcboyxhy 2009-10-14
  • 打赏
  • 举报
回复
如果是linux,在你调用malloc/free的时候,实际上C运行库已经为你做过优化了。
glibc有一套自己的内存管理方式,用来优化malloc/free。

内核为每个进程维护一个页表,当你的malloc无法在已经分配的页中分配,
或者实际需要空间大于1个page长度的时候,内核会给你分配新的页,放入到页表中。
页表也是要占用一定空间的。

比较坏的情况下,你malloc了1byte,但是实际消耗了8k
gxlzlu 2009-10-14
  • 打赏
  • 举报
回复
说到底,就是现在的操作系统已经不需要按照2的幂次方来分配内存了。
哦耶!!!
wesweeky 2009-10-14
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 dollfacedboyfriend 的回复:]
有必要讲下堆,malloc是分配在堆上的,我给一个典型的堆的实现.假设我有3.5k,将我的内存分为127块如下:
8byte:  64块
16byte:  32块
32byte:  16块
64byte:  8块
128byte: 4块
256byte: 2块
512byte: 1块
我会对每一块内存做一个索引表,标志每块的内存使用情况.
假如我要去分配8byte,那么我会先遍历64块8byte的内存块,如果用完,再去遍历16byte的,依次下去!
假如我malloc(9),8byte的块是不行的,我必须遍历16byte,好,找到空闲的,那么好就用它吧,问题来了,我16byte的剩下了7byte,如果我以后用不到7byte以下的内存,它就浪费了!
这就是为什么我们建议用malloc(8),malloc(16)这样的方式,你也可以针对你的系统,写段测试程序来确定你的堆是如何管理的!
堆的好处是速度快,只需要简单的数组下标访问就可以达到目的!缺点就在于内存空间的浪费比较严重.
因为大部分堆的实现是不会像我上面所说的会去使用那7byte的内存!大部分堆的实现为了效率,直接将一个分配过内存的块标记为used,也就是说一个块,只能同时给一个malloc.这样就会有这样的情况出现了,如果我所有的256byte的都用完,我要分一个132byte的内存,那么我只能使用512byte的,内存的使用率大大降低!为了尽量避免这样的情况,使用malloc(8),malloc(16),malloc(32)之类的分配方式,和尽量缩短malloc分配到的内存的使用周期是一个有效的途径!可以大大增加内存利用率!
另外,这个例子中,我的堆的设计,最大的为512byte,也就是说,这个例子里,malloc只能分到最大512byte的内存!
讲完收工!
[/Quote]

受益匪浅
todo9351 2009-10-14
  • 打赏
  • 举报
回复
我觉得malloc的实现是按不同系统自身实现的, 如果是用slab分配的话, 要申请多少,就是多少字节, 而且不一定是2的幂次方, 当然, 你也可以选择常规分配, 那就是2的幂次方了, 一些细节的话, 可以看 slab分配器的相关内容.
楼主一直关心的内存块的信息问题. 在有的系统中, 是将此信息放在内存块的头部, 有的系统(如伙伴系统)中, 则是统一管理,不需要存信息在头部.
^_^
www_adintr_com 2009-10-12
  • 打赏
  • 举报
回复
只要是 4 的倍数就可以了吧,没听说过按2的幂次方来分配的,你从哪里看来的?
Johnny_Lx 2009-10-12
  • 打赏
  • 举报
回复
编译器会为你分配的,你可以把内存当成一个链表来使用,在你malloc的时候,编译器会在链表意外的地方把该内存的信息,如大小、指针等,以便于管理。 所以其实这些东西不用我们关心的。
用户 昵称 2009-10-12
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 hpsmouse 的回复:]
经过多次实验,发现的确有多余的。
C/C++ code#include<stdlib.h>
#include<stdio.h>int main()
{char* p= (char*)malloc(16);char* q= (char*)malloc(16);
printf("0x%lx\n0x%lx\ndiff: %ld\n", p, q, q-p);
p= (char*)malloc(24);
q= (char*)malloc(24);
printf("0x%lx\n0x%lx\ndiff: %ld\n", p, q, q-p);
p= (char*)malloc(32);
q= (char*)malloc(32);
printf("0x%lx\n0x%lx\ndiff: %ld\n", p, q, q-p);
p= (char*)malloc(48);
q= (char*)malloc(48);
printf("0x%lx\n0x%lx\ndiff: %ld\n", p, q, q-p);
p= (char*)malloc(64);
q= (char*)malloc(64);
printf("0x%lx\n0x%lx\ndiff: %ld\n", p, q, q-p);return0;
}
我故意没有 free。
某次运行结果:
Assembly code0x642010
0x642030diff:32
0x642050
0x642070diff:32
0x642090
0x6420c0diff:48
0x6420f0
0x642130diff:64
0x642170
0x6421c0diff:80
这个差值至少是 32,然后每个分配都是 16 Byte 的 Padding。
仅供参考……
[/Quote]

就是在栈中申请的普通变量,其实也是按某个值(如16)进行对齐的。
canican 2009-10-12
  • 打赏
  • 举报
回复
0x431fa0
0x431f60
diff: -64
0x431f10
0x431ec0
diff: -80
0x431e70
0x431e20
diff: -80
0x431dc0
0x431d60
diff: -96
0x431cf0
0x431c80
diff: -112

vc6,运行结果跟你的不一样
opposever 2009-10-12
  • 打赏
  • 举报
回复
这个完全是操作系统决定的,你malloc之后,操作系统一般会加几个标识(比如记录申请的大小、指向内存块的指针、指向申请函数的PC指针),用来后面检查测试使用。
所以实际使用内存是你申请的加上操作系统加的。
当然,你可以自己些个操作系统,定义一个malloc函数,申请多少就是多少^_^
loveour 2009-10-12
  • 打赏
  • 举报
回复
也许需要2的幂次是以前的说法吧?我在VS2008下试验下面的代码是成功的
#include <stdlib.h>   // For _MAX_PATH definition
#include <stdio.h>
#include <malloc.h>

int main( void )
{
char *string;

// Allocate space for a path name
string =(char*) malloc( _MAX_PATH);

// In a C++ file, explicitly cast malloc's return. For example,
// string = (char *)malloc( _MAX_PATH );

if( string == NULL )
printf( "Insufficient memory available\n" );
else
{
printf( "Memory space allocated for path name\n" );
free( string );
printf( "Memory freed\n" );
}
}

这是MSDN文档里面的范例,_MAX_PATH改成30,31都可以通过编译并正确运行。
MSDN里面还有这样一句话,“The block may be larger than size bytes because of space required for alignment and maintenance information.“,也就是实际分配的内存会比申请的大,因为要对其以及有管理和维护的信息,内存对齐还需要,但是对齐不需要我们来做.
corn107 2009-10-12
  • 打赏
  • 举报
回复
mark~
gxlzlu 2009-10-11
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 hpsmouse 的回复:]
经过多次实验,发现的确有多余的。
C/C++ code#include<stdlib.h>
#include<stdio.h>int main()
{char* p= (char*)malloc(16);char* q= (char*)malloc(16);
printf("0x%lx\n0x%lx\ndiff: %ld\n", p, q, q-p);
p= (char*)malloc(24);
q= (char*)malloc(24);
printf("0x%lx\n0x%lx\ndiff: %ld\n", p, q, q-p);
p= (char*)malloc(32);
q= (char*)malloc(32);
printf("0x%lx\n0x%lx\ndiff: %ld\n", p, q, q-p);
p= (char*)malloc(48);
q= (char*)malloc(48);
printf("0x%lx\n0x%lx\ndiff: %ld\n", p, q, q-p);
p= (char*)malloc(64);
q= (char*)malloc(64);
printf("0x%lx\n0x%lx\ndiff: %ld\n", p, q, q-p);return0;
}
我故意没有 free。
某次运行结果:
Assembly code0x642010
0x642030diff:32
0x642050
0x642070diff:32
0x642090
0x6420c0diff:48
0x6420f0
0x642130diff:64
0x642170
0x6421c0diff:80
这个差值至少是 32,然后每个分配都是 16 Byte 的 Padding。
仅供参考……
[/Quote]
还是兄弟的动手能力强呀。。。
哎,我辞职后自己的本子上就没装工作用的软件,呵呵!!!

分析一下实践结果:
0x642010
0x642030
diff: 32 malloc(16),增加16个字节
0x642050
0x642070
diff: 32 malloc(24),增加8个字节
0x642090
0x6420c0
diff: 48 malloc(32),增加16个字节
0x6420f0
0x642130
diff: 64 malloc(48),增加16个字节
0x642170
0x6421c0
diff: 80 malloc(64),增加16个字节

分析结果:貌似现在不在需要按照2的幂次方来申请内存了。
最典型的就是malloc(64),最终分配了80个字节。还有就是malloc(32)。
靠,以前所学的又废了。
有搞操作系统的大牛来给兄弟们指点迷津么??

ht_61743904 2009-10-11
  • 打赏
  • 举报
回复
标记下
加载更多回复(25)

70,037

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧