2010-03-17 12 views
5

Ich habe gerade mit C angefangen und habe sehr wenig Wissen über Leistungsprobleme mit malloc() und free(). Meine Frage ist diese: wenn ich malloc() gefolgt von free() innerhalb einer while Schleife anrief, die für, sagen wir, 20 Wiederholungen läuft, würde es langsamer laufen als das Rufen free()außerhalb die Schleife?C Programmierung: malloc und frei innerhalb einer Schleife

Ich verwende tatsächlich die erste Methode, um Speicher einem Puffer zuzuordnen, eine Zeichenfolge variabler Länge aus einer Datei zu lesen, einige Zeichenfolgenoperationen auszuführen und den Puffer nach jeder Iteration dann zu löschen. Wenn meine Methode viel Aufwand verursacht, würde ich gerne nach einem besseren Weg für mich fragen, um die gleichen Ergebnisse zu erzielen.

+5

Sie nicht frei außerhalb der Schleife aufrufen können, wenn Sie malloc im Inneren anrufen, oder Sie den Speicher für alle, aber die malloc aus der letzten Iteration auslaufen. Sie können jedoch realloc anstelle von malloc verwenden und dann außerhalb freigeben. – Cascabel

+0

@Jefromi: Ich denke, du solltest diesen Kommentar eine Antwort geben. –

+2

Ihr Englisch ist in Ordnung - es ist in der Tat besser als die meisten Neulinge Englisch auf SO. –

Antwort

13

Auf jeden Fall langsamer. (Aber erinnern Sie sich die Anzahl der malloc und free ausgleichen müssen Sie sonst einen Speicherverlust bekommen.)

Wenn die Länge variiert, können Sie realloc verwenden, um die Puffergröße zu erweitern.

void* v = malloc(1024); 
size_t bufsize = 1024; 

while(cond) { 
    size_t reqbufsize = get_length(); 
    if (reqbufsize > bufsize) { 
     bufsize = reqbufsize * 2; 
     v = realloc(v, bufsize); 
    } 
    // you may shrink it also. 

    do_something_with_buffer(v); 
} 

free(v); 
+2

+1 - aber denkst du nicht 'bufsize = reqbufsize * 2;' ist ein wenig drastisch? : P –

+0

Vielleicht. Die MSVC2k8-Implementierung von 'std :: vector' vergrößert den Puffer bei der Neuzuweisung um 150%. –

+4

@BillyONeal: Das ist eigentlich eine ziemlich übliche Art, Dinge zu tun. – Dinah

3

Wenn Sie die maximale Länge des Puffers kennen oder ein vernünftiges Maximum festlegen können, können Sie für jede Iteration denselben Puffer verwenden. Sonst was du machst, sollte in Ordnung sein.

0

Es hängt von der Implementierung von malloc und frei.

Der beste Weg, um Ihre Frage zu beantworten ist eine Benchmark zu bauen ...

1

Es hängt davon ab, wofür Sie den Puffer benötigen.

Müssen Sie es wirklich nach jeder Iteration löschen oder vielleicht ein \0 Zeichen am Ende würde ausreichen, um das Ende einer Zeichenfolge zu markieren? Nach all dem benutzen die verschiedenen Bibliotheksaufrufe str.

Wenn Sie es wirklich löschen müssen, können Sie bzero() verwenden. Sicheres Mallozieren und Freigeben bei jeder Iteration ist eine Verschwendung von Ressourcen, da Sie den Puffer problemlos wiederverwenden können.

Ein anderes Problem würde auftreten, wenn Sie die for-Schleife parallelisieren würden, d. H. Mehrere gleichzeitige Threads verwenden, die es verwenden.

Einfaches Beispiel aus der Praxis: Mit einem Eimer Wasser transportieren. Angenommen, Sie müssen mehrere Trips mit diesem Bucket machen: Wäre es sinnvoll, es aufzuheben, zu benutzen, abzulegen, wieder aufzuheben, zu benutzen, etc ...? Sie können den Bucket so oft wie möglich erneut verwenden. Wenn andererseits der Bucket von Ihnen und mehr Personen verwendet werden muss, organisieren Sie entweder den Zugriff auf den Bucket oder benötigen mehr Buckets.

Letzter Vorschlag: Mach dir keine Sorgen über die Leistungen jetzt. Sie sagen, dass frühe Optimierung die Wurzel allen Übels ist, und du wirst bald verstehen, warum.

Erstens, verstehen Sie das Problem: Schreiben Sie Code, der weggeworfen werden kann. Experiment. Zweitens, testen Sie es. Stellen Sie sicher, dass es das tut, was Sie brauchen. Drittens optimieren Sie es. Lassen Sie die Schleife zehntausend Mal laufen und messen Sie, wie lange es dauert. Verschieben Sie dann das Malloc nach draußen und messen Sie erneut (verwenden Sie den Shell-Befehl time, falls unter UNIX). Viertens, schreiben Sie es um, weil Ihr erstes Experiment höchstwahrscheinlich ein Durcheinander von Patches aus try-retry-Code sein wird, der nicht funktioniert.

Spülen, wiederholen.

ps: habe Spaß in der Zwischenzeit. Es soll interessant und nicht frustrierend sein.

1

Generell sollte alles, was außerhalb einer Schleife verschoben werden kann, sein. Warum wiederholen Sie die gleiche Aktion, wenn Sie es nur einmal tun können?

Justin Ethier hat Recht, einen Puffer zuweisen, der bequem die größte Zeichenfolge passt und diese wieder verwendet.

6

Für 20 Iterationen sollten Sie sich keine Gedanken über die Leistung von malloc/free machen.

Sogar für weit mehr (ein paar Größenordnungen), sollten Sie nicht über Optimierungen nachdenken, bis Sie den Code profilieren und verstehen, was langsam ist.

Wenn Sie den Puffer freigeben möchten, müssen Sie ihn erst löschen. Selbst wenn Sie das malloc/free-Objekt außerhalb der Schleife verschieben (mit einem von Justin vorgeschlagenen maximalen Puffer), sollten Sie den Puffer nicht explizit löschen müssen.

6

Sie können außerhalb der Schleife nicht frei anrufen, wenn Sie malloc innerhalb nennend:

char * buffer; 
for (int i = 0; i < num_files; i++) { 
    buffer = malloc(proper_length(i)); 
    // do some things with buffer 
} 
free(buffer); 

Sie num_files mal malloc'ed haben, aber nur einmal befreit - Sie den Speicher sickerte aus allen außer dem letzten !

Es gibt zwei Hauptwahlen - malloc vor der Schleife (oder auch nur ein Array verwenden), wenn Sie eine Größe kennen, die für alles funktionieren wird, oder realloc verwenden:

char * buffer = NULL; 
for (int i = 0; i < num_files; i++) { 
    buffer = realloc(proper_length(i)); 
    // do some things with buffer 
} 
free(buffer); 
0

Prozess es besser. Haben Sie etwas Pseudo-Code:

#define BLOCK_SIZE 1024 // or about the bigger size of your strings. 

char *buffer = (char *) malloc(BLOCK_SIZE) 

for(int i=0; i<20; i++) 
{ 
    while (more bytes left to read) 
    { 
    read full string or BLOCK_SIZE bytes at max // most calls work this way 
    proces bytes in buffer 
    } 
} 

free(buffer); 
Verwandte Themen