2011-09-30 65 views
14

我发送一个文本文件 - 客户端服务器 将文本分解成每个512字节的数据包 但某些数据包包含的文本小于最大大小,因此在服务器端接收每个数据包时我调用malloc()再次建立一个字符串,这是一个不好的做法? 保持一个可以适应最大长度的工作缓冲区并保持迭代,复制和覆盖它的值会更好吗?继续调用malloc()和free()会有多糟糕?

好的@n.m。这里是代码,这个如果是在一个for(;;)循环内被select()唤醒()

if(nbytes==2) { 
      packet_size=unpack_short(short_buf); 
      printf("packet size is %d\n",packet_size); 
      receive_packet(i,packet_size,&buffer); 
      printf("packet=%s\n",buffer); 
      free(buffer); 
} 
//and here is receive_packet() function 
int receive_packet(int fd,int p_len,char **string) { 
*string = (char *)malloc(p_len-2); // 2 bytes for saving the length  
char *i=*string; 
int temp; 
int total=0; 
int remaining=p_len-2; 
while(remaining>0) { 
    //printf("remaining=%d\n",remaining); 
    temp = recv(fd,*string,remaining,0); 
    total+=temp; 
    remaining=(p_len-2)-total; 
    (*string) += temp; 
} 
*string=i; 
return 0; 
} 
+0

一行代码值得一千个评论。 –

+0

@ n.m。我将代码添加到主帖 – cap10ibrahim

回答

11

在你的例子中,你的函数已经包含一个系统调用,所以malloc/free的相对成本几乎不可测量。在我的系统上,“往返”平均约为300个周期,并且系统调用(获取当前时间,pid等)至少需要2500个周期。预计recv很容易花费10倍,在这种情况下,分配/释放内存的成本至多约为该操作总成本的1%。

当然,确切的时间安排会有所不同,但粗略的数量级在整个系统中应该是相当不变的。我甚至不会考虑删除malloc/free作为优化,除非是纯粹是用户空间的函数。在没有动态分配的情况下,可能实际上更有价值的是在不应该出现失败情况的操作中 - 这里的值是您简化了加固您可以不必担心当malloc失败时该怎么办。

+0

我觉得很难相信你的malloc/free只需要300个周期。你是否正在使用一个碎片堆,并且包含需要从操作系统中引入新内存并释放它的malloc? –

+1

我正在计算'free(malloc(1));'(在Linux/glibc/i686上,使用'rdtsc'测量)何时不需要从操作系统映射新内存,只需重新使用先前释放的内存。这几乎总是常见的情况。您只需要担心从操作系统获得新内存的时间就是实时编程,您可以关心任何操作的**最差情况**延迟,而不是程序的整体运行时间。 –

+3

使用初始化为NULL的随机大小的malloc/free随机分配插槽的10-100个分配数组将是更好的测试。 –

1

只有测试可以告诉。当用C语言编程时,我尽量避免使用malloc,因为如果你偶然创建一个内存泄漏可能很难解决。

7

与调用malloc和free相关的开销。一个块必须从堆中分配,并在使用时标记为已使用,当你释放出现时。不知道你正在使用的操作系统或编译器,这可能在c库或OS内存管理级别。由于你正在做很多malloc和释放,你可以在你的堆没有足够的连续空闲内存的地方使用malloc来分割你的堆。如果您只能分配一个缓冲区并继续使用它,那通常会更快,并且堆碎片的危险更小。

+2

如果他一遍又一遍地分配和释放一个固定大小的块,他几乎肯定不会分解任何东西。 (这并不意味着没有开销......但在这种情况下,碎片可能不是原因。) – Nemo

+0

假设没有别的从程序堆中分配内存,并且它是单线程的,我同意。它可能每次都返回相同的内存块。但是,我们不知道程序中还有哪些内容是从堆中分配的,或者如何实现这个特定的堆管理器。 – user957902

3

我发现malloc,realloc和free很贵。如果你可以避免malloc,最好重用你已经拥有的内存。

编辑:
它看起来像我错了多少昂贵的malloc是。在Linux上使用GNU C库版本2.14一些时间测试显示,该循环10万次分配和释放512个插槽与1个随机大小,以163840个字节的测试:

tsc average loop = 408 
tsc of longest loop = 294350 

所以浪费了408个循环做malloc或在一个紧密的内部循环中做new将是一件愚蠢的事情。除此之外,别担心这一点。

+0

感谢您的反馈 – cap10ibrahim

1

衡量两种解决方案的性能。通过分析或测量吞吐量。确实无法说出任何事情。