我正在发送一个文本文件 - 客户端 - 服务器 将文本分解为每个512字节的数据包 但是有些数据包包含小于最大大小的文本,所以在服务器端收到每个数据包时我正在调用malloc()再次构建一个字符串,这是一个不好的做法吗? 保持一个适合最大长度的工作缓冲区并继续迭代,复制和覆盖它的值会更好吗?
好吧@n.m。这是代码,这个if在select()唤醒的for(;;)循环中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 :(得分:15)
在您的示例中,您的函数已包含系统调用,因此malloc
/ free
的相对成本几乎无法衡量。在我的系统上,malloc
/ free
“往返”平均约300个周期,最便宜的系统调用(获取当前时间,pid等)成本至少2500次循环。期望recv
容易花费10倍,在这种情况下,分配/释放内存的成本最多约为此操作总成本的1%。
当然,确切的时间会有所不同,但粗略的数量级应该在各个系统中相当不变。我甚至不会考虑删除malloc
/ free
作为优化,除了纯粹用户空间的函数。在没有动态分配的情况下实际上更有价值的是在不应该有故障情况的操作中 - 这里的值是你简化并且强化你的代码而不必担心malloc
失败时该怎么做。
答案 1 :(得分:7)
调用malloc和free会产生开销。一个块必须从堆中分配并标记为正在使用,当你释放出来的时候。不知道您使用的操作系统或编译器,这可能在c库或OS内存管理级别。由于你正在做很多mallocs和释放,你可能会破坏你的堆,你可能没有足够的连续可用内存在别处做malloc。如果你只能分配一个缓冲区并继续重用它,那通常会更快,并且堆碎片的危险性也会降低。
答案 2 :(得分: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个循环来执行malloc
或new
将是一件愚蠢的事情。除此之外,不用担心它。
答案 3 :(得分:2)
Malloc通常相当便宜。如果它生成一个系统调用以获得更多的堆空间,那么它的成本很高。例如,在UNIX-Like系统中,它最终将生成一个昂贵的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并释放部分循环,我会得到这些时间:
time ./test
real 0m0.009s
user 0m0.005s
sys 0m0.005s
所以你看到malloc和free确实有开销,虽然我认为只是开销几十倍就是非常多的开销。
如果它可以一次又一次地重复使用相同的堆(如此处的情况),则速度特别快。当然,如果我不断重复分配和增加程序,则需要更多时间,因为这会导致一些系统调用。
当然,您的里程可能因操作系统,编译器和stdlib实现而异。
答案 4 :(得分:1)
只有测试可以说明。在使用C语言进行编程时,我会避免使用malloc,因为如果您偶然创建内存泄漏,则很难解决内存泄漏问题。
答案 5 :(得分:1)
调用多个malloc / free实际上可以增加进程使用的内存(不涉及任何泄漏),如果传递给malloc的大小是可变的,正如这个问题所证明的那样:
C program memory usage - more memory reported than allocated
所以单缓冲方法可能是最好的。
答案 6 :(得分:1)
测量两种解决方案的性能。通过分析或测量吞吐量。无法肯定地说出任何事情。