21

テキストファイルを送信しています-クライアントサーバーはテキストをそれぞれ512バイトのパケットに分割しますが、一部のパケットには最大サイズ未満のテキストが含まれているため、サーバー側で各パケットを受信するときにmalloc()を呼び出して文字列を再度構築します、これは悪い習慣ですか?最大長に収まる作業バッファを保持し、その値を反復、コピー、上書きし続ける方が良いですか?

わかりました @nm ここにコードがあります。これは、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;
 }
4

7 に答える 7

26

あなたの例では、関数には既に syscall が含まれているため、malloc/の相対的なコストはfree実質的に測定不能になります。私のシステムでは、malloc/ free「往復」は平均して約 300 サイクルであり、最も安価なシステムコール (現在の時刻、pid などを取得する) は少なくとも 2500 サイクルかかります。recv簡単にその 10 倍のコストがかかると予想されます。この場合、メモリの割り当て/解放のコストは、この操作の総コストのせいぜい約 1% になります。

もちろん、正確なタイミングはさまざまですが、大まかな桁数はシステム間でかなり不変です。純粋にユーザー空間である関数を除いて、最適化としてmalloc/を削除することを検討し始めることすらありません。free動的割り当てを使用しない方がおそらく実際にはより価値があるのは、失敗のケースがあってはならない操作です。ここでの価値は、失敗したときに何をすべきかを心配する必要がないため、コードを簡素化して強化するmallocことです。

于 2011-09-30T19:32:46.577 に答える
7

mallocおよびfreeの呼び出しに関連するオーバーヘッドがあります。ブロックをヒープから割り当てて、使用中としてマークする必要があります。解放すると、リビジョンが発生します。使用しているOSまたはコンパイラがわからない場合、これはcライブラリまたはOSメモリ管理レベルにある可能性があります。多くのmallocとfreeを実行しているため、他の場所でmallocを実行するのに十分な連続した空きメモリがない場合に、ヒープを大幅に断片化する可能性があります。バッファを1つだけ割り当てて再利用できる場合は、通常、より高速になり、ヒープの断片化の危険性が低くなります。

于 2011-09-30T15:11:05.163 に答える
4

malloc、realloc、および free はかなり高価であることがわかりました。malloc を回避できる場合は、既に取得しているメモリを再利用することをお勧めします。

編集:
malloc がどれだけ高価かについて、私は間違っているようです。Linux で GNU C ライブラリ バージョン 2.14 を使用したいくつかのタイミング テストでは、100,000 回ループし、1 から 163840 バイトまでのランダムなサイズで 512 個のスロットを割り当てて解放するテストについて、次のことが示されています。

tsc average loop = 408
tsc of longest loop = 294350

mallocしたがって、実行中またはタイトな内部ループで408 サイクルを無駄newにするのはばかげたことです。それ以外は気にしないでください。

于 2011-09-30T15:21:04.567 に答える
3

Malloc は一般的にかなり安価です。より多くのヒープ スペースを取得するために syscall を生成する場合にのみ、コストがかかります。たとえば、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 個の整数を割り当てて解放し、これを 100 万回行います。かなり控えめな小さな 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 にはオーバーヘッドがあることがわかりますが、何もしない場合のオーバーヘッドの 10 倍強は、非常に大きなオーバーヘッドだと思います。

同じヒープのチャンクを何度も再利用し続けることができれば、特に高速です (ここの場合のように)。もちろん、プログラムの割り当てと拡張を繰り返し続けると、syscall がいくつか発生するため、さらに時間がかかります。

もちろん、走行距離は OS、コンパイラ、および 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

2 つのソリューションのパフォーマンスを測定します。プロファイリングまたはスループットの測定による。確かなことを言うことは不可能です。

于 2011-09-30T15:52:09.613 に答える