|
蓝森林 http://www.lslnet.com 2006年6月6日 10:18
calloc函数的效率
昨天上网,看到一些代码用calloc函数写的。申请内存的函数,平时不常用。因为不常用,所以见了便想它为什么不常用呢?是不是它和malloc+memset函数的效率有差别啊?所以写了验证程序,一看,果然如此,calloc函数的效率要比malloc+memset函数的效率低一点。测试如下:
环境:
[code]
Red Hat Linux release 8.0 (Psyche)
Kernel 2.4.18-14smp on an i686
login: yangwl
Password:
[/code]
测试办法:用calloc函数申请100个字节的空间,申请1亿次,记时。用malloc+memset函数完成同样的工作,记时。比较两次记时的大小。
自己猜想后简单的测试代码及结果:
[code]
[yangwl:/home/users50/yangwl/test]$ cat time.c
#include <stdio.h>;
#include <stdlib.h>;
#include <time.h>;
#include <string.h>;
int main(void) {
int i;
char *p;
time_t t;
t = time(0);
printf("begin...\n");
for ( i = 0; i < 100000000; i++) {
#ifdef CA
p = (char *)calloc(100,sizeof(char));
#endif
#ifdef MA
p = (char *)malloc(100*sizeof(char));
memset(p,0,100);
#endif
if ( p == NULL ) {
printf("calloc error!\n");
exit(1);
}
free(p);
}
t = time(0) - t;
printf("%ld\n",t);
exit(0);
}
[yangwl:/home/users50/yangwl/test]$ gcc -o ca time.c -O2 -DCA
[yangwl:/home/users50/yangwl/test]$ gcc -o ma time.c -O2 -DMA
[yangwl:/home/users50/yangwl/test]$ ./ca
begin...
33
[yangwl:/home/users50/yangwl/test]$ ./ma
begin...
32
[yangwl:/home/users50/yangwl/test]$ ./ca
begin...
33
[yangwl:/home/users50/yangwl/test]$ ./ma
begin...
31
[yangwl:/home/users50/yangwl/test]$ ./ca
begin...
34
[yangwl:/home/users50/yangwl/test]$ ./ma
begin...
32
[yangwl:/home/users50/yangwl/test]$
[/code]
怕自己因为测的次数少,结果不正确,所以写一个长期测试的程序,下班放在服务器上运行。将结果写入文件,测试代码及结果如下:
[code]
[yangwl:/home/users50/yangwl/test]$ cat time.c
#include <stdio.h>;
#include <stdlib.h>;
#include <time.h>;
#include <string.h>;
time_t ma(FILE *);
time_t ca(FILE *);
int main(void) {
int i,
count = 0,
true = 0,
false = 0;
time_t t,
tmp;
struct tm *tforp;
FILE *fp1,*fp2;
fp1 = fopen("./log1","w");
if ( fp1 == NULL ) {
printf("log1 open error!\n");
exit(1);
}
fp2 = fopen("./log2","w");
if ( fp2 == NULL ) {
printf("log2 open error!\n");
exit(1);
}
t = time(0);
tforp = localtime(&t);
fprintf(fp1,"begin time:%d-%d-%d %d:%d:%d\n",tforp->;tm_year+1900,tforp->;tm_mon+1,tforp->;tm_mday,
tforp->;tm_hour,tforp->;tm_min,tforp->;tm_sec);
fprintf(fp2,"begin time:%d-%d-%d %d:%d:%d\n",tforp->;tm_year+1900,tforp->;tm_mon+1,tforp->;tm_mday,
tforp->;tm_hour,tforp->;tm_min,tforp->;tm_sec);
for ( i = 0; i < 10*60; i++ ) {
tmp = ca(fp2)-ma(fp2);
fprintf(fp2," %ld",tmp);
tmp >; 0 ? true++ : false++;
count++;
}
fprintf(fp1,"true:%d\nfalse:%d\ncount:%d\n",true,false,count);
t = time(0);
tforp = localtime(&t);
fprintf(fp1,"end time:%d-%d-%d %d:%d:%d\n",tforp->;tm_year+1900,tforp->;tm_mon+1,tforp->;tm_mday,
tforp->;tm_hour,tforp->;tm_min,tforp->;tm_sec);
fprintf(fp2,"end time:%d-%d-%d %d:%d:%d\n",tforp->;tm_year+1900,tforp->;tm_mon+1,tforp->;tm_mday,
tforp->;tm_hour,tforp->;tm_min,tforp->;tm_sec);
fclose(fp1);
fclose(fp2);
exit(0);
}
time_t ma(FILE *fp2) {
int i;
char *p;
time_t t;
t = time(0);
for ( i = 0; i < 100000000; i++) {
p = (char *)malloc(100*sizeof(char));
memset(p,0,100);
if ( p == NULL ) {
fprintf(fp2,"calloc error!\n");
exit(1);
}
free(p);
}
t = time(0)-t;
return t;
}
time_t ca(FILE *fp2) {
int i;
char *p;
time_t t;
t = time(0);
for ( i = 0; i < 100000000; i++) {
p = (char *)calloc(100,sizeof(char));
if ( p == NULL ) {
fprintf(fp2,"calloc error!\n");
exit(1);
}
free(p);
}
t = time(0)-t;
return t;
}
[yangwl:/home/users50/yangwl/test]$ cat log1
begin time:104-8-8 19:19:22
true:586
false:14
count:600
end time:70-0-1 21:1:21
[yangwl:/home/users50/yangwl/test]$ cat log2
begin time:104-8-8 19:19:22
2 2 1 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1 2 1 2 1 2 1 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 1 2 2 2 2 2 1 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 1 0 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 1end time:70-0-1 21:1:21
[yangwl:/home/users50/yangwl/test]$
[/code]
结果:果然calloc函数的效率要稍微低一点,平均差2sec,少数差1sec,极少可以做到几乎不差。要注意,结果只能精确到sec。
猜想原因:有一个很明显的能看出来的差别是,calloc函数要在函数运行中计算总共开辟多大空间。而malloc函数的参数只有一个,在上面的程序钟,这个参数是一个可以在编译的过程中就确定大小的表达式,因此能事先确定开辟空间的大小。但是,性能的差别仅仅在于一个乘法操作吗?
bug:呵呵,大家可以看出来,log文件中的日期时间有问题。是因为忘记了localtime的用法,以及取时间语句的一个错误,昨天着急写程序所致,不过并不影响结果。
意外:本来一次循环应该耗时1分多钟,所以我定了600次循环,本来以为可以让它运行一晚上,结果看log,2个小时不到就结束了,不知道为什么,是服务器在晚上的运算速度提高了?还是经常性的“分配”“释放”,系统的内存管理机制习惯了这样的动作导致“熟能生巧”了?[/code] |
calloc函数的效率
-->
不是这样的. |
calloc函数的效率
-->
怎么不是呢?
calloc(100,sizeof(char))是一定要做一个100*sizeof(char)的动作的,而
malloc(100*sizeof(char))里面,不是可以在编译的时候就确定sizeof的值,而且将100*1这样的算式直接优化成100这个值吗?好像编译器都有这样的优化吧? |
calloc函数的效率
>;>; 系统的内存管理机制习惯了这样的动作导致“熟能生巧”了
我来帮你解释吧。
因为局部引用的特性 和 cpu的高速缓存的作用。它高速缓存了指令和数据,如果命中都是在一级缓存的话,该缓存的速度和cpu是一样的,如果是二级缓存命中的话,二级缓存速度是cpu的一半。不管怎么样,还是比没有缓存命中的速度高很多。经过长时间运行,高速缓存算法淘汰了其他进程的缓存,可以认为,长时间运行时,缓存的都是这个进程的数据和代码。
也可能还有mmu的TLB寄存器起作用,开始访问数据和代码的时候是需要经过mmu进行虚拟地址到物理地址的转换,运行一段时间以后,这些地址已经保存在了TLB里面,它也是和cpu等速度的。一旦高速缓存中没有命中,也不需要付出地址变换的代价。
还有就是存储器替换算法的作用,因为开始运行的时候,内存中的进程比较多,一次分配大存储空间是需要较长时间查找,因为可能有内存碎片,如果还没有找到你需要的大空间的话,OS会选择替换内存数据,直到找到符合请求的内存。
而长时间运行后,一些进程OS会将他交换出物理内存,这样的话,就可以组成更大的空闲空间,os在进行内存分配请求的时候就不需要花很多时间来进行查找。
所以“熟能生巧” :lol: |
calloc函数的效率
| calloc函数的效率
呵呵,大家学习 |
calloc函数的效率
看了ljttlf的解释,对为什么总体运行时间少了有了一点认识。
可是,关于为什么calloc没有melloc+memset快还是没有解开,继续聆听,期待中…… |
calloc函数的效率
-->
并不是"malloc函数可以在编译的过程中就确定开辟空间的大小",而是"编译器可以在编译的过程中就确定常量表达式的值",与malloc函数没有关系. |
calloc函数的效率
呵呵,谢谢JohnBull老大。自己表述的有问题呢。^_^。改过来了。 |
calloc函数的效率
没有乘法操作。
100*sizeof(char)是个常数=100,在编译时就确定。 |
calloc函数的效率
但是calloc函数里面一定是有一个乘法操作的,我说的是这个。
因为100和sizeof(char)是用两个参数传进函数里面的。 |
calloc函数的效率
N个常数的任何操作(+ - * / )等编译后就是一个常数。
编译时就计算了。 |
calloc函数的效率
-->
一句话,认真看我的帖子了吗?这个东西谁都知道。 |
calloc函数的效率
啊,SORRY,你是说里面有乘法操作。
两个应该基本差不多,CALLOC慢点你测的结果应该是对的吧。 |
calloc函数的效率
>;>;malloc函数的参数只有一个,这个参数可以在编译的过程中就确定开辟空间的大小。
呵呵,你说的还是有问题呀。
比如:
[code]
char *ptr = (char *)malloc(n*i);
[/code]
n和i为程序中的变量,你说编译的时候能确定大小吗? |
calloc函数的效率
我想问个问题:
下面是我在网上找到的。
1。为具有num_elems个长度为elem_size元素的数组分配内存。
2。calloc()用来配置num_elems个相邻的内存单位,每一单位的大小为elem_size
3。在内存动态存储区中分配n块长度为"size"字节的连续区域。函数的返回值为该区域的首地址。calloc函数与malloc 函数的区别仅在于一次可以分配n块区域。
我的问题是,
calloc分配内存快,是在大小为elem_size的内存快之间连续
还是在在整个大内存快间连续?(地址为num_elems * elem_size大小) |
calloc函数的效率
| calloc函数的效率
-->
都应该是连续的吧?应该和malloc一样吧,只不过多了一个清0的动作。 |
| |