Memory leaking? Bitte um Hinweise

F

fizzibubbele

Aktives Mitglied
Thread Starter
Dabei seit
03.02.2009
Beiträge
143
Reaktionspunkte
26
Bin noch auf Kriegsfuß mit der Speicherverwaltung von ObjC. Leckt der folgende Code? Das in newId erzeuge Objekt wird ja nicht mehr released?

.h:
#import <Cocoa/Cocoa.h>

@interface LSPersonId : NSObject {
int personId;
}
+ (LSPersonId*) newId;
@end

.m:
@implementation LSPersonId

+ (LSPersonId*) newId {
return [[LSPersonId alloc] init];
}

- (id) init {
self = [super init];
if (self != nil) {
personId = 10000000;
}
return self;
}
@end
 
Nie mehr? Wenn ich das richtig sehe, ist das ein normales Factory-Pattern. Natürlich muss sich dann der Aufrufer der Factory um das Freigeben des Speichers bemühen. Die Antwort ist also: Jein.

Edit: 108 war schneller ;)
 
  • Gefällt mir
Reaktionen: fizzibubbele
In einigen Büchern habe ich gelesen, dass autorelease "böse" ist. Aber hier war es jetzt zumindest meine Lösung :)
 
das problem mit dem autorelease ist halt, dass du nie weißt wann das objekt dann released wird.
kann halt zum crash führen, wenn du dann drauf zugreifst...
 
In einigen Büchern habe ich gelesen, dass autorelease "böse" ist. Aber hier war es jetzt zumindest meine Lösung :)

Welches Buch war das?

Die Factory Methode ist richtig, sie hat das "new…" Prefix. Damit ist klar, dass das Object dem Aufrufer gehört, und der Aufrufer die Verantwortung hat, ein release zu schicken. Das sagt Dir auch der Analyzer so.

Also: Jeder der [LSPerson newId] aufruft, muss das entstandene Object auch releasen. Mit relase oder autorelease.

Allerdings ist weicht das vom normalen Convenience Allocator ab; der gibt immer ein Object mit Autorelease zurück.

@108: Natürlich weiss man, wann ein Object mit Autorelease released wird. Es ist ja kein Garbage Collector

Alex
 
Natürlich weiss man, wann ein Object mit Autorelease released wird. Es ist ja kein Garbage Collector

Also ich hatte das Problem, dass sich eine Instanz Variable mit autorelease mal da und mal nicht da war, also der Zugriff darauf crashte...
 
Ohne Deinen Code jetzt genau zu kennen möchte ich sagen: Natürlich, eine Instanzvariable mit autorelease freizugeben ist ja auch falsch.

Aber nochmal zu den Büchern: Das interessiert mich wirklich brennend, wer so etwas schreibt. Entweder wurde es falsch verstanden, vielleicht ist es auch missverständlich geschrieben, oder da schreibt jemand gefährlichen Blödsinn.

Alex
 
In einigen Büchern habe ich gelesen, dass autorelease "böse" ist. Aber hier war es jetzt zumindest meine Lösung :)
Das kann nicht deine Lösung gewesen sein, weil es in dem von dir geposteten Code kein Problem zu lösen gab. Solltest du trotzdem ein Problem gehabt haben, dann poste bitte auch den ganzen Code. Vermutlich hattest du irgendwo in dem Code der LSPersonId verwendet einen Memoryleak, den du mit einem autorelease in newId an der absolut falschen Stelle „behoben“ hast.
 
  • Gefällt mir
Reaktionen: fizzibubbele
Das kann nicht deine Lösung gewesen sein, weil es in dem von dir geposteten Code kein Problem zu lösen gab. Solltest du trotzdem ein Problem gehabt haben, dann poste bitte auch den ganzen Code. Vermutlich hattest du irgendwo in dem Code der LSPersonId verwendet einen Memoryleak, den du mit einem autorelease in newId an der absolut falschen Stelle „behoben“ hast.

...kann sein, ich habe da so eine Vermutung. Wenn ich wieder Zeit habe, poste ich mal den Rest.
 
Könntest Du bitte noch mal posten, in welchen Büchern Du das mit "Autorelease ist böse" gelesen hast? Das finde ich sehr wichtig.

Danke

Alex
 
Da es wichtig ist, habe ich noch mal die Bücher gescannt, die ich gelesen habe (Aaron Hillegas und Cocoa in a Nutshell) - und muss gestehen, dass die Bücher keine Wertung vornehmen - also nehme ich meine Behauptung zurück.

Woher ich diesen negativen Beigeschmack habe, kann ich leider nicht sagen, vermutlich aus irgendwelchen Online-Tutorials oder Forendiskussionen (nicht hier). Die Begründung ging aber in die Richtung von 108.

Inn meinem Code habe ich das autorelease wie folg eingefügt:

+ (LSPersonId*) newId
{
return [[[LSPersonId alloc] init] autorelease];
}


Warum hier und kein release in der aufrufenden Klasse? Weil ich einen Convenient Constructor (analog stringWithFormat: etc) bauen wollte. Und soweit ich gelesen habe (in der Xcode Doku;)), haben diese Convenient Allocator eben einen autorelease eingebaut -> daher die Lösung für mein Problem (am Ende also das, was below schrieb).

Wie verhält sich ein Convenient Constructor eigentlich, wenn es keinen NSAutoreleasePool gibt? Fehlermeldungen habe ich da nicht erhalten.
 
Zuletzt bearbeitet:
Nie mehr? Wenn ich das richtig sehe, ist das ein normales Factory-Pattern. Natürlich muss sich dann der Aufrufer der Factory um das Freigeben des Speichers bemühen. Die Antwort ist also: Jein.

Edit: 108 war schneller ;)

Diese Aufteilung der Erzeugung/Freigabe verstößt gegen die Regeln der Speicherverwaltung in Cocoa. Das ist also bereits ein Fehler, bloß einer, den man mit noch einem Verstoß "beseitigen" kann.
 
das problem mit dem autorelease ist halt, dass du nie weißt wann das objekt dann released wird.
kann halt zum crash führen, wenn du dann drauf zugreifst...

Es ist klar, wann das Objekt freigegeben wird.
 
  • Gefällt mir
Reaktionen: below
Da es wichtig ist, habe ich noch mal die Bücher gescannt, die ich gelesen habe (Aaron Hillegas und Cocoa in a Nutshell) - und muss gestehen, dass die Bücher keine Wertung vornehmen - also nehme ich meine Behauptung zurück.

Woher ich diesen negativen Beigeschmack habe, kann ich leider nicht sagen, vermutlich aus irgendwelchen Online-Tutorials oder Forendiskussionen (nicht hier). Die Begründung ging aber in die Richtung von 108.

Inn meinem Code habe ich das autorelease wie folg eingefügt:

+ (LSPersonId*) newId
{
return [[[LSPersonId alloc] init] autorelease];
}


Warum hier und kein release in der aufrufenden Klasse? Weil ich einen Convenient Constructor (analog stringWithFormat: etc) bauen wollte. Und soweit ich gelesen habe (in der Xcode Doku;)), haben diese Convenient Allocator eben einen autorelease eingebaut -> daher die Lösung für mein Problem (am Ende also das, was below schrieb).

Wie verhält sich ein Convenient Constructor eigentlich, wenn es keinen NSAutoreleasePool gibt? Fehlermeldungen habe ich da nicht erhalten.

Doch, es gibt einen Fehler. Aus dem Kopp: "-autorelease with no autorelease pool in place. Just leaking." oder so.

Da im Main-Thread automatisch ein ARP angelegt wird, kan dir das da schon enmal nicht passieren. Du kannst aber mal einen Thread starten und dort an $irgendwen ein -autorelease schicken. Sollte zum Laufzeitfehler führen.
 
  • Gefällt mir
Reaktionen: below
Wie Amin schon gesagt hat, gibt es einen Fehler.

Du hast den Convenience Allocator auch eigentlich richtig angelegt. Für Schönheitspunkte sollte er aber nicht mit "new..." Anfangen, da dies im üblichen Cocoa Sprachgebrauch eine Methode anzeigt, die KEIN Autorelease Object zurückgibt. Das ist aber nur für den Analyzer und für die Lesbarkeit des Codes.

Viel wichtiger ist, dass Du weisst, wie man mit einem solchen Objekt umgeht. Der Fehler ist -- so oder so -- nicht in dem Code, den Du gepostet hast.

Alex

P.S.: Und danke für's nachkucken. Das ist irgendwie ein hartnäckiges Gerücht, das autorelease "böse" ist, und dem muss man mit aller Entschiedenheit entgegentreten. Sowas ist, um es ganz freundlich zu sagen, klassisches "gefährliches Halb- (oder Nicht-)wissen"
 
  • Gefällt mir
Reaktionen: fizzibubbele
[…]P.S.: Und danke für's nachkucken. Das ist irgendwie ein hartnäckiges Gerücht, das autorelease "böse" ist, und dem muss man mit aller Entschiedenheit entgegentreten. Sowas ist, um es ganz freundlich zu sagen, klassisches "gefährliches Halb- (oder Nicht-)wissen"

Na, ja, ist Apple auch selbst schuld. Ich weiß noch, wie ich vor jahren allerorten ein paar auf den Deckel bekommen habe, weil ich strikt für CA oder +alloc-init…-autorelease eingetreten bin. Auch hier. Und es gab genug Beispiele aus altem Samplecode, in dem es auch noch so stand. Da verteidige mal die Ansicht gegen Leute, die nicht selbst nachdenken. Das landet dann auch schnell in der Literatur. Inzwischen sagt Apple aber selbst, dass sich die Verwendung von CA anbietet.

Als es mit dem iPhone losging, war es auf dem ersten Tech-Talk auch noch so, dass die von -autorelease abrieten, weil das Speicher länger belegt. Dabei gibt es dafür wirklich effektivere Varianten. Inzwischen machen sie es AFAIK auch nicht mehr.
 
Für Schönheitspunkte sollte er aber nicht mit "new..." Anfangen, da dies im üblichen Cocoa Sprachgebrauch eine Methode anzeigt, die KEIN Autorelease Object zurückgibt. Das ist aber nur für den Analyzer und für die Lesbarkeit des Codes.
Hauptsächlich ist das für irgendeinen Dritten, der die Klasse später benutzt. Der sieht new..., und macht einen *relase auf das Objekt wie es sich gehört. Später knallt es dann an anderer Stelle, weil das Objekt einmal zu viel freigegeben werden soll. Das ist schon mehr als ein rein optischer Makel.

Das ist eine sträfliche Missachtung der Speicherverwaltungregeln. Die werden zwar nicht formal durch die Sprache erzwungen sind aber Grundlage dessen, dass überhaupt irgendein Programm funktioniert.
 
  • Gefällt mir
Reaktionen: below
Hauptsächlich ist das für irgendeinen Dritten, der die Klasse später benutzt. Der sieht new..., und macht einen *relase auf das Objekt wie es sich gehört. Später knallt es dann an anderer Stelle, weil das Objekt einmal zu viel freigegeben werden soll. Das ist schon mehr als ein rein optischer Makel.

Ja, ich habe das vielleicht ein wenig zu locker dargestellt. Auch der llvm-clang Analyzer erkennt das new... und liefert, falls es falsch verwendet wurde, irreführende Fehlermeldungen.

Alex
 
Zurück
Oben Unten