Ist es in Ordnung, “klassisches” malloc()/free() in Objective-C/iPhone-Apps zu verwenden?

Lesezeit: 8 Minuten

Benutzeravatar von Philippe Leybaert
Philippe Leybaert

Ich habe eine Weile mit der iPhone-Entwicklung herumgespielt, und obwohl es sich ein bisschen unangenehm anfühlt, wenn Sie ein „Hardcore“-.NET-Entwickler sind, ist es nicht so schlimm, wenn Sie sich daran gewöhnt haben.

In jedem Buch, das ich über Objective-C lese, wird nur darüber gesprochen retain/release (Referenzzählung) für die Speicherverwaltung. Als C/C++-Entwickler der alten Schule scheint es seltsam, dass die Zuweisung auf die “normale” Weise erfolgt, indem malloc() und free() wird nur in einigen Fußnoten erwähnt.

ich weiß das malloc() und free() arbeite in Objective-C, aber ich bin gespannt, ob es gängige Praxis ist oder nicht. Wenn ich ein Array von 100 Ganzzahlen zuweisen möchte, scheint dies schließlich der effizienteste Weg zu sein:

int *array = malloc(sizeof(int) * 100);

memset(array,0,sizeof(int) * 100);

// use the array

free(array);

Ist dies tatsächlich der beste Weg, oder sollte ich die einfache C-Speicherverwaltung vermeiden?

Es gibt einen Objective-C-Wrapper um Rohspeicher, den ich gerne für ähnliche Aufgaben verwende: NSMutableData. Es hat den Vorteil, dass Sie die Eigentumsrechte beibehalten/freigeben und das Array einfach erweitern kann (ohne dass Sie die Neuzuweisung selbst vornehmen müssen).

Ihr Code würde wie folgt aussehen:

NSMutableData* data = [NSMutableData dataWithLength:sizeof(int) * 100];
int* array = [data mutableBytes];
// memory is already zeroed

// use the array

// decide later that we need more space:
[data setLength:sizeof(int) * 200];
array = [data mutableBytes]; // re-fetch pointer in case memory needed to be copied

// no need to free
// (it's done when the autoreleased object is deallocated)

  • Ich mag diese Antwort @Nikolai Ruhe. Ich habe ein “malloc”ed Array als Eigenschaft verwendet. Ich hatte 3 Objekte dieser Klasse und habe das Array in Dealloc “befreit”. Nach dem Freigeben des ersten Objekts erhielt ich jedoch einen Fehler “malloc: *** error for object 0x70a60: freigegebener Zeiger wurde nicht zugewiesen”, als ich das zweite freigab!? Sieht so aus, als ob der Malloc auf “Klassenebene” und nicht auf “Objektebene” durchgeführt wurde. Durch den Wechsel zu Ihrer Lösung ist dies verschwunden, aber auch das “Verhalten” der Objekte hat sich geändert. Noch nicht sicher warum.

    – iPadEntwickler2011

    2. März 2011 um 2:16 Uhr

  • OK, ich habe das versucht und zu meinem Entsetzen festgestellt, dass sich mein “Array” mit zufälligen Bits füllte. Ich denke, die zugrunde liegenden “Daten” wurden automatisch freigegeben, bevor ich mit dem Array fertig war. Das Setzen eines „retain“ auf die Daten hat dieses Problem behoben, aber jetzt muss ich einen Verweis auf das „data“-Objekt beibehalten, was diese Lösung weniger attraktiv macht.

    – iPadEntwickler2011

    2. März 2011 um 4:24 Uhr

  • @iPadDeveloper2011 Sie müssen den Memory Management Programming Guide unter erneut lesen developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/…

    – Nikolai Ruhe

    2. März 2011 um 9:06 Uhr

  • @iPadDeveloper2011: Sie müssen Ihre Speicherverwaltung auffrischen. In diesem speziellen Fall werden die Daten automatisch freigegeben. Solange der Autorelease-Pool nicht geleert wird, ist dieser Code in Ordnung, aber sobald Sie einen Bereich erreichen, in dem möglicherweise ein Autorelease-Pool vorhanden ist, der geleert werden könnte, können Sie die Daten nicht mehr verwenden. Wenn Sie es länger brauchen, dann müssen Sie es tun retain es, und dann release es, wenn Sie fertig sind.

    – Adam Rosenfield

    2. März 2011 um 15:49 Uhr

  • Ich für meinen Teil liebe diese Antwort. Ich habe mich immer geärgert, wenn ich Arrays von Ints verwenden muss und die Referenzzählung verliere und sie einfach erweitern kann. Danke für die sehr gute Erklärung und Beispiele!

    – Accatyyc

    21. Februar 2012 um 20:56 Uhr


Es ist völlig in Ordnung – Objective-C ist eine strenge Obermenge von C, wenn Sie also einfaches C schreiben möchten, hindert Sie nichts daran. In vielen Fällen ist es vorteilhaft zu verwenden malloc und free um den Overhead der Objective-C-Laufzeit zu vermeiden.

Wenn Sie beispielsweise ein Array mit einer unbekannten Anzahl von Ganzzahlen dynamisch zuweisen müssen, ist dies oft einfacher und einfacher:

int *array = malloc(N * sizeof(int));  // check for NULL return value!
// use array[0]..array[N-1]
...
free(array);

Gegen:

NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:N];
// use NSMutableArray methods to do stuff with array; must use NSNumbers instead
// of plain ints, which adds more overhead
...
[array release];

Ich arbeitete an einem Wortspiel für das iPhone, und wir mussten ein Multi-Megabyte-Wörterbuch mit gültigen Wörtern laden. Die Wortliste wurde in einen Riesen geladen char Array zugewiesen mit malloc(), mit einigen cleveren Optimierungen, um die Speichergröße noch weiter zu reduzieren. Offensichtlich ist für so etwas der Aufwand für die Verwendung von an NSArray ist auf dem limitierten iPhone völlig unpraktisch. Ich weiß nicht genau, was der Overhead ist, aber es ist sicherlich mehr als ein Byte pro Zeichen.

  • RE: ‘strenge Obermenge’. Obwohl ich Ihnen persönlich (stark) zustimme, ist diese Aussage technisch gesehen nicht wahr, da wir über die Entwicklung von Apple/iPhone sprechen. Apple definiert es so: Objective-C syntax is a superset of GNU C/C++ syntax. Strenge Obermenge hat eine sehr spezifische Bedeutung, wobei die uneingeschränkte Verwendung von Obermenge die geringere der beiden ist (denken Sie an „verhält sich wie“ vs. „genau wie“). Der Qualifizierer von syntax schränkt es weiter bis zu dem Punkt ein, an dem es fast nutzlos ist, wodurch Apples Verpflichtung zu Anhang A der C99-Spezifikation effektiv auf knapp 16 Seiten von 552 im Standard beschränkt wird.

    – Johannes

    20. Juli 2009 um 5:49 Uhr

  • Ich hatte eine Reihe von Problemen mit malloc/free in Objective C. Siehe meinen Kommentar zu Nikolais Antwort. Abgesehen davon hatte ich Probleme mit dem Zuweisen (Kopieren) von Zeigern auf malloced Arrays, um das malloced Array zwischen Objekten zu teilen.

    – iPadEntwickler2011

    2. März 2011 um 2:25 Uhr

  • Es stimmt zwar, dass Sie malloc() und free() verwenden können, aber Sie können den größten Teil des Laufzeit-Overheads vermeiden, indem Sie stattdessen ein NSMutableData mit angemessener Länge verwenden.

    – Steven Fischer

    2. Mai 2014 um 2:34 Uhr

Natürlich Du kann Verwenden Sie diese Funktionen, da Objective-C lediglich eine Obermenge von C ist. Es ist jedoch ziemlich ungewöhnlich, so etwas zu tun, da Objective-C Objekte und Möglichkeiten enthält, dies zu vereinfachen.

Schließlich könnten Sie den obigen Code wie folgt schreiben:

NSMutableArray *array = [[NSMutableArray alloc] init];

//Use the array, adding objects when need be

[array release];

Obwohl Sie erstellen müssten NSNumber Objekte zu speichern ints (seit NSArray erlaubt nicht das Hinzufügen von Nicht-Objekttypen), ist es im Allgemeinen üblicher, Objekte zu verwenden, da es einfacher ist, Daten zu verschieben, und die Array-Klassen häufiger mit anderen Cocoa-Klassen integriert sind und die Speicherverwaltung im Allgemeinen ist einfacher als die Standard-C-Speicherverwaltung.

Auch wenn Sie beginnen, Objekte aus dem Array hinzuzufügen oder daraus zu entfernen, dann machen die Cocoa-Array-Objekte dies viel einfacher.

  • Dies scheint ein Overkill zu sein, wenn Sie ein einfaches Array von Ganzzahlen benötigen. Besonders die Notwendigkeit, NSNumber-Objekte zu erstellen, erscheint mir so ineffizient. Was ist, wenn ich ein Array von 100.000 booleschen Werten zuweisen möchte?

    – Philippe Leybaert

    19. Juli 2009 um 19:35 Uhr

  • Möglicherweise gibt es im Vergleich zur Verwendung einfacher Arrays von Ganzzahlen einen geringfügigen Overhead. Aber sie werden sicherlich häufiger verwendet als die Verwendung von C-Speicherverwaltung. Und wenn Sie ein Array von 100.000 booleschen Werten zuweisen, gibt es möglicherweise einen besseren Weg als die derzeitige Implementierung (es sei denn, dies ist ein hypothetisches Szenario).

    – Alex Rozanski

    19. Juli 2009 um 19:41 Uhr

  • Dies ist besonders übertrieben, wenn Sie es mit wirklich einfachen Objekten zu tun haben. Wenn Sie beispielsweise MineSweeper für das iPhone erstellen würden, ist dies der Fall Größenordnungen Es ist schneller, ein Quadrat zu einer Struktur zu machen und ein Array von Strukturen zu mallocieren, als die Quadrate als Objekte zu erstellen und sie in ein NSArray zu stecken. Außerdem benötigen Sie etwas weniger Speicher.

    – David DeLong

    19. Juli 2009 um 19:41 Uhr

  • Natürlich hängt es vom Kontext der Frage ab, aber die Verwendung von Standard-C-Speicherverwaltung ist ziemlich ungewöhnlich. Außerdem können sie, wie gesagt, nützlicher werden, wenn Sie die Array-Elemente manipulieren.

    – Alex Rozanski

    19. Juli 2009 um 19:44 Uhr

  • Ich möchte nur darauf hinweisen, dass ein Array von 100.000 booleschen Werten (BOOLs?) Bereits eine speicherineffiziente Lösung ist, da jedes BOOL 1 Byte ist, aber Sie wirklich nur 1 Bit benötigen. Es ist also etwa 8x besser, ein Array von 100.000/8 Zeichen und bitweise Operatoren zu verwenden.

    – iPadEntwickler2011

    2. März 2011 um 2:59 Uhr

Wenn Sie es mit Standard-C-Typen zu tun haben, ist es nicht weniger üblich oder “OK” als in C. So wird es in C gemacht, das ein Teil von Objective-C ist.

Es ist auch nicht ungewöhnlich, eine Art Objekt-Wrapper um diese Dinge zu schreiben, um sie mit dem Rest von Cocoa (KVO, Speicherverwaltung usw.) in Einklang zu bringen. Sie könnten also eine IntArray-Klasse erstellen, die das tut mallochinter den Kulissen, damit Sie sie nach Bedarf speichern und freigeben können. Beachten Sie, dass dies nicht unbedingt erforderlich ist – es kann nur praktisch sein, wenn diese Art von Struktur ein wichtiger Teil Ihres Programms ist.

Es ist völlig in Ordnung, malloc zu verwenden, und Sie können Ihre eigene Speicherverwaltung durchführen. Eigentlich NSObject allocWithZone: verwendet malloc, um den Speicher abzurufen.

  • Es ist technisch Calloc, aber ja. =)

    – David DeLong

    19. Juli 2009 um 19:43 Uhr

  • Eigentlich ist es technisch NSAllocateObject(). Was dann passiert, ist komplizierter. Unter ObjC2 mit aktiviertem GC, NSAllocateObject() Anrufe objc_allocate_object(). Unter ObjC2 ohne GC oder ObjC < 2, NSAllocateObject() Anrufe class_createInstanceFromZone()die wiederum anruft malloc_zone_calloc()was, wie der Name schon sagt, logisch äquivalent zu ist calloc(). EIN calloc() mit einer count von 1 ist per definitionem unverdaulich aus einer Zuordnung, die durch erhalten wurde malloc vom selben size das hat seine space is initialized to all bits zero (C99 7.20.3.1.2).

    – Johannes

    20. Juli 2009 um 5:17 Uhr

  • Es ist technisch Calloc, aber ja. =)

    – David DeLong

    19. Juli 2009 um 19:43 Uhr

  • Eigentlich ist es technisch NSAllocateObject(). Was dann passiert, ist komplizierter. Unter ObjC2 mit aktiviertem GC, NSAllocateObject() Anrufe objc_allocate_object(). Unter ObjC2 ohne GC oder ObjC < 2, NSAllocateObject() Anrufe class_createInstanceFromZone()die wiederum anruft malloc_zone_calloc()was, wie der Name schon sagt, logisch äquivalent zu ist calloc(). EIN calloc() mit einer count von 1 ist per definitionem unverdaulich aus einer Zuordnung, die durch erhalten wurde malloc vom selben size das hat seine space is initialized to all bits zero (C99 7.20.3.1.2).

    – Johannes

    20. Juli 2009 um 5:17 Uhr

1412040cookie-checkIst es in Ordnung, “klassisches” malloc()/free() in Objective-C/iPhone-Apps zu verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy