蓝森林首页 | 返回主页 | 本站地图 | 站内搜索 | 联系信箱 |
 您目前的位置:首页 > 自由软件 > 技术交流 > 应用编程


    

蓝森林 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的动作。



Copyright © 1999-2000 LSLNET.COM. All rights reserved. 蓝森林网站 版权所有。 E-mail : webmaster@lslnet.com