21

我正在发送一个文本文件 - 客户端-服务器将文本分解为每个 512 字节的数据包,但一些数据包包含的文本小于最大大小,因此在服务器端接收每个数据包时我正在调用 malloc() 再次构建一个字符串,这是一种不好的做法吗?保留一个适合最大长度的工作缓冲区并继续迭代、复制和覆盖其值是否更好?

好的@nm这里是代码,这个 if 在 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;
 }
4

7 回答 7

26

malloc在您的示例中,您的函数已经包含一个系统调用,因此/的相对成本free几乎无法衡量。在我的系统上,一次“malloc往返free”平均大约需要 300 个周期,而最便宜的系统调用(获取当前时间、pid 等)至少需要 2500 个周期。预计recv很容易花费 10 倍,在这种情况下,分配/释放内存的成本最多约为该操作总成本的 1%。

当然,确切的时间会有所不同,但粗略的数量级在整个系统中应该是相当不变的。除了纯用户空间的函数外,我什至不会开始考虑删除malloc/free作为优化。没有动态分配可能实际上更有价值的是在不应该有失败情况的操作中 - 这里的价值是你简化强化你的代码,而不必担心malloc失败时该怎么做。

于 2011-09-30T19:32:46.577 回答
7

调用 malloc 和 free 会产生开销。当您释放 revese 时,必须从堆中分配一个块并将其标记为正在使用。不知道您使用的是什么操作系统或编译器,这可能在 c 库或操作系统内存管理级别。由于您正在执行大量 malloc 和释放操作,因此您可能最终会严重分割您的堆,而您可能没有足够的连续空闲内存来在其他地方执行 malloc。如果您可以只分配一个缓冲区并继续重用它,那通常会更快并且堆碎片的危险更小。

于 2011-09-30T15:11:05.163 回答
4

我发现 malloc、realloc 和 free 非常昂贵。如果您可以避免 malloc ,最好重用您已经拥有的内存。

编辑:
看起来我对 malloc 的昂贵程度是错误的。在 Linux 上使用 GNU C 库 2.14 版进行的一些计时测试表明,对于循环 100,000 次并分配和释放 512 个随机大小从 1 到 163840 字节的插槽的测试:

tsc average loop = 408
tsc of longest loop = 294350

所以浪费 408 个循环来做mallocnew在一个紧凑的内部循环中是一件愚蠢的事情。除此之外不用担心。

于 2011-09-30T15:21:04.567 回答
3

Malloc 通常相当便宜。如果它生成一个系统调用来获得更多的堆空间,它只会很昂贵。例如,在类 UNIX 系统中,它最终会生成一个昂贵的 sbrk 调用。如果你反复 malloc 和释放相同大小的内存,它会做的很快。例如,考虑以下小测试程序:

#include <stdlib.h>


int main()
{
  int i=0;
  int *ptr;

  for(int i=0; i<1e6; i++) {
    ptr = malloc(1024*sizeof(int));
    free(ptr);
  }
}

它分配 1024 个整数并释放它们,并执行一百万次。在我相当谦虚的小 chromebook 变成 linux 机器上运行它,我得到的时间看起来像这样:

time ./test

real    0m0.125s
user    0m0.122s
sys     0m0.003s

现在,如果我注释掉循环的 malloc 和 free 部分,我会得到这些时间:

time ./test

real    0m0.009s
user    0m0.005s
sys 0m0.005s

因此,您会看到 malloc 和 free 确实有开销,尽管我认为不做任何事情的开销只是十倍以上的开销是非常多的。

如果它可以一遍又一遍地重复使用相同的堆块(就像这里的情况一样),它会特别快。当然,如果我不断地重复分配和增长程序,这将需要更多时间,因为这会导致一些系统调用。

当然,根据操作系统、编译器和 stdlib 实现,您的工作量可能会有所不同。

于 2018-05-24T14:47:22.690 回答
2

如果传递给 malloc 的大小是可变的,则调用多个 malloc/free 实际上可以增加进程使用的内存(不涉及任何泄漏),如以下问题所示:

C 程序内存使用情况 - 报告的内存多于分配的内存

所以单缓冲方法可能是最好的。

于 2011-09-30T15:20:00.307 回答
1

只有测试才能判断。在 CI 中编程时,避免 malloc 是错误的,因为如果您不小心创建了内存泄漏,则很难修复它。

于 2011-09-30T15:09:45.653 回答
1

测量两种解决方案的性能。通过分析或测量吞吐量。不可能肯定地说什么。

于 2011-09-30T15:52:09.613 回答