Wenn ARC versagt...

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Wenn ARC versagt...

    Hi,

    ich hatte heute einen interessaten Fall, wo man tatsächlich trotz ARC noch selber einen AP braucht. Dabei war das gar nicht mal so ein exotischer Anwendungsfall und eventuell gilft es dem einen oder anderen Anfänger zu wissen was man machen muss wenn man in so eine Situation kommt:

    Es ging darum, aus einem Template-String einen XML-String zu erzeugen. Im Template stehen Placeholder ala @@@@@WasWeißIch@@@@@ und diese werden dann durch die Werte aus den Objekten ersetzt. Ich hatte nun ca. 400 Objecte mit je ca. 20 Attributen, was bei meinem ursprünglichen Code zu einem Speicherverbrauch von über 80MB geführt hat und damit meine App auf einem alten iPad zum Absturz brachte.

    Im Code sah das dann so aus:

    Quellcode

    1. NSString *xmlString=... <- hier wird der XML String intialisiert mit Header etc.
    2. for(MeinObject object in meineObjecte)
    3. {
    4. NSString *objectTemplate=[self getXMLFromRessource:RESSOURCE_TEMPLATE_SPEICHERE_BBFELD]; <- ist der TemplateString
    5. NSString *xmlObject=[xmlObject stringByReplacingOccurrencesOfString:PLACEHOLDER_VALUE1 withString:object.value1];
    6. xmlObject=[xmlObject stringByReplacingOccurrencesOfString:PLACEHOLDER_VALUE2 withString:object.value2];
    7. xmlObject=[xmlObject stringByReplacingOccurrencesOfString:PLACEHOLDER_VALUE3 withString:object.value3];
    8. ....
    9. xmlString=[xmlString stringByAppendigString:xmlObject];
    10. }
    Alles anzeigen


    Was hier nun passiert ist eigentlich klar. Es wird rund 400*20 mal ein alter String durch einen neuen ersetzt. Damit verliert man die Referenz auf den alten String und denkt sich "Ok das räumt ARC auf". Stimmt ja auch. Doch dummerweise kommt ARC innerhalb der Schleife überhaupt nicht zum Zuge. Der AutoreleasePool wird nämlich erst frühestens nach dem Verlassen der Methode aufgerufen in der diese Schleife steht. Somit wird schön brav der Speicher verbraten, bis die App letztendlich vom System verwarnt wird und dann abgeschossen...

    Abhilfe schafft in diesem Fall ein eigener AutoreleasePool innerhalb der Schleife. Also ganz einfach

    Quellcode

    1. NSString *xmlString=... <- hier wird der XML String intialisiert mit Header etc.
    2. for(MeinObject object in meineObjecte)
    3. {
    4. @autoreleasepool
    5. {
    6. NSString *objectTemplate=[self getXMLFromRessource:RESSOURCE_TEMPLATE_SPEICHERE_BBFELD]; <- ist der TemplateString
    7. NSString *xmlObject=[xmlObject stringByReplacingOccurrencesOfString:PLACEHOLDER_VALUE1 withString:object.value1];
    8. xmlObject=[xmlObject stringByReplacingOccurrencesOfString:PLACEHOLDER_VALUE2 withString:object.value2];
    9. xmlObject=[xmlObject stringByReplacingOccurrencesOfString:PLACEHOLDER_VALUE3 withString:object.value3];
    10. ....
    11. xmlString=[xmlString stringByAppendigString:xmlObject];
    12. }
    13. }
    Alles anzeigen


    Nun werden nach jedem Schleifendurchlauf die alten Strings freigegeben und man benötigt nur noch 1/400 des Speichers.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Michael schrieb:

    Na ja, das Problem existiert bei manuellem Reference Counting genauso und die Lösung war da auch schon ein lokaler Autoreleasepool.


    Habe ja auch nicht das Gegenteil behauptet. Nur das man sich damals noch ums Memory gekümmert hat und von daher für so etwas einfach sensibilisierter war und heute denkt man "Geht ja eh alles automatisch".

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:

    Habe ja auch nicht das Gegenteil behauptet.

    Du schriebst 'Wenn ARC versagt…', was impliziert, dass Du behauptest, ARC hätte in dem Fall versagt.
    Das wiederum impliziert, unter MRR wäre so etwas nicht passiert. Und das ist faktisch falsch.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • warum werden die objekte eigentlich nicht released/deallokiert in dem moment in dem der retaincount (der ja automatisch geführt wird) auf 0 geht?)
    also ca so:

    Quellcode

    1. ​some code
    2. {
    3. NSString *s = [NSString stringWithContetnsFromFile:...];
    4. NSLog(@"the description: %@", s):
    5. } <-- hier soltle das string-objekt von mir aus gesehen dealloziert werden weil rc auf 0 geht
    6. other code
  • AFAIK wird es genau so gemacht.
    Mit diesen geschweiften Klammern leitet man ja einen eigenen Scope ein, nach dem dann aufgeräumt wird.

    Insofern müsste Thallius' Code auch ohne das @autorelease vor den geschweiften Klammern zuverlässig funktionieren.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Marco Feltmann schrieb:

    AFAIK wird es genau so gemacht.
    Mit diesen geschweiften Klammern leitet man ja einen eigenen Scope ein, nach dem dann aufgeräumt wird.

    Insofern müsste Thallius' Code auch ohne das @autorelease vor den geschweiften Klammern zuverlässig funktionieren.


    das hab ich eben auch gedacht. dann hat er maximal die 20 strings gleichzeitig welche aber wohl nicht 80 MB belegen. vor dem nächsten der 400 durchläufe werden die letzten 20 strings ja gelöscht (meiner meinung nach).
    und das problem der 20 strings würde man ganz einfach mittels eines einzigen mutable-strings lösen ;)
  • gritsch schrieb:

    Marco Feltmann schrieb:

    AFAIK wird es genau so gemacht.
    Mit diesen geschweiften Klammern leitet man ja einen eigenen Scope ein, nach dem dann aufgeräumt wird.

    Insofern müsste Thallius' Code auch ohne das @autorelease vor den geschweiften Klammern zuverlässig funktionieren.


    das hab ich eben auch gedacht. dann hat er maximal die 20 strings gleichzeitig welche aber wohl nicht 80 MB belegen. vor dem nächsten der 400 durchläufe werden die letzten 20 strings ja gelöscht (meiner meinung nach).
    und das problem der 20 strings würde man ganz einfach mittels eines einzigen mutable-strings lösen ;)


    tja das müsst ihr dann wohl Apple fragen.
    ohne AP geht es jedenfalls nicht.

    gruss

    claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:

    gritsch schrieb:

    Marco Feltmann schrieb:

    AFAIK wird es genau so gemacht.
    Mit diesen geschweiften Klammern leitet man ja einen eigenen Scope ein, nach dem dann aufgeräumt wird.

    Insofern müsste Thallius' Code auch ohne das @autorelease vor den geschweiften Klammern zuverlässig funktionieren.


    das hab ich eben auch gedacht. dann hat er maximal die 20 strings gleichzeitig welche aber wohl nicht 80 MB belegen. vor dem nächsten der 400 durchläufe werden die letzten 20 strings ja gelöscht (meiner meinung nach).
    und das problem der 20 strings würde man ganz einfach mittels eines einzigen mutable-strings lösen ;)


    tja das müsst ihr dann wohl Apple fragen.
    ohne AP geht es jedenfalls nicht.

    gruss

    claus


    doch, mit einem mutable-string benötigst du nur noch ca ein zwanzigstel!
  • gritsch schrieb:

    SteveJ schrieb:

    Thallius schrieb:

    das müsst ihr dann wohl Apple fragen.


    Oder einfach mal die Dokumentation lesen. „2 Stunden Try & Error erspart 10 Minuten Handbuchlesen“ passt schon.


    es geht aber darum dass sich nicht ARC um die objekte kümmert sondern eben der ARP. und das ist vielen wohl nicht klar (mir auch nicht bisher weil ich nur MRC verwende (riesen projekt)).


    Äh - was? Autorelease Pools sind zentraler Bestandteil des auf Referenzzählung basierenden Speichermanagements von Cocoa, Automatic Reference Counting kümmert sich und die automatische Referenzzählung, wie der Name schon sagt.

    Das du wegen deines „Riesenprojekts“ die letzen drei Jahre unter einem Stein verbracht und die modernen Errungenschaften von Clang verpasst hast tut mir leid, vielleicht solltest Du einfach mal wieder eine Schulung machen oder so was. Es gibt ja genügend Objective-C-Kurse, einige sogar von Mitgliedern in diesem Forum...
  • SteveJ schrieb:

    gritsch schrieb:

    SteveJ schrieb:

    Thallius schrieb:

    das müsst ihr dann wohl Apple fragen.


    Oder einfach mal die Dokumentation lesen. „2 Stunden Try & Error erspart 10 Minuten Handbuchlesen“ passt schon.


    es geht aber darum dass sich nicht ARC um die objekte kümmert sondern eben der ARP. und das ist vielen wohl nicht klar (mir auch nicht bisher weil ich nur MRC verwende (riesen projekt)).


    Äh - was? Autorelease Pools sind zentraler Bestandteil des auf Referenzzählung basierenden Speichermanagements von Cocoa, Automatic Reference Counting kümmert sich und die automatische Referenzzählung, wie der Name schon sagt.

    Das du wegen deines „Riesenprojekts“ die letzen drei Jahre unter einem Stein verbracht und die modernen Errungenschaften von Clang verpasst hast tut mir leid, vielleicht solltest Du einfach mal wieder eine Schulung machen oder so was. Es gibt ja genügend Objective-C-Kurse, einige sogar von Mitgliedern in diesem Forum...


    nein, ARC macht eben NICHT das gleiche wie ARP. Siehe Convenient constructors in ARC
  • gritsch schrieb:

    SteveJ schrieb:


    Äh - was? Autorelease Pools sind zentraler Bestandteil des auf Referenzzählung basierenden Speichermanagements von Cocoa, Automatic Reference Counting kümmert sich und die automatische Referenzzählung, wie der Name schon sagt.


    nein, ARC macht eben NICHT das gleiche wie ARP.


    Du scheinst etwas verwirrt. Wo steht etwas von „macht das Gleiche“? Automatic Reference Counting nutzt Autorelease Pools, Autorelease Pools sind älter als Automatic Reference Counting und wissen (fast) nichts davon.

    Aber, wie gesagt: Autorelease Pools sind zentraler Bestandteil des auf Referenzzählung basierenden Speichermanagements von Cocoa. Ohne Referenzzählung keine automatische Referenzzählung, also ohne Autorelease Pools auch kein Automatic Reference Counting. Automatic Reference Counting und Garbage Collection schließen einander aus, Automatic Reference Counting bedingt Autorelease Pools.
  • SteveJ schrieb:

    gritsch schrieb:

    SteveJ schrieb:


    Äh - was? Autorelease Pools sind zentraler Bestandteil des auf Referenzzählung basierenden Speichermanagements von Cocoa, Automatic Reference Counting kümmert sich und die automatische Referenzzählung, wie der Name schon sagt.


    nein, ARC macht eben NICHT das gleiche wie ARP.


    Du scheinst etwas verwirrt. Wo steht etwas von „macht das Gleiche“? Automatic Reference Counting nutzt Autorelease Pools, Autorelease Pools sind älter als Automatic Reference Counting und wissen (fast) nichts davon.

    Aber, wie gesagt: Autorelease Pools sind zentraler Bestandteil des auf Referenzzählung basierenden Speichermanagements von Cocoa. Ohne Referenzzählung keine automatische Referenzzählung, also ohne Autorelease Pools auch kein Automatic Reference Counting. Automatic Reference Counting und Garbage Collection schließen einander aus, Automatic Reference Counting bedingt Autorelease Pools.


    quatsch, warum soll es keine manuelle referenzzählung ohne ARP geben? natürlich gibt es das! und folglich kann es auch automatische refernzzählung ohne ARP geben!
  • gritsch schrieb:

    SteveJ schrieb:

    Aber, wie gesagt: Autorelease Pools sind zentraler Bestandteil des auf Referenzzählung basierenden Speichermanagements von Cocoa.


    quatsch, warum soll es keine manuelle referenzzählung ohne ARP geben? natürlich gibt es das! und folglich kann es auch automatische refernzzählung ohne ARP geben!


    Nö, gibt es nicht, siehe die Memory Management Policy. Du brauchst in Cocoa einen Autorelease Pool, sonst gibt es kein Deferred Release.

    NSAutoreleasePool Class Reference schrieb:

    In a reference counted environment, Cocoa expects there to be an autorelease pool always available.
    ...
    In a garbage-collected environment, there is no need for autorelease pools.


    Cocoa ohne Autorelease Pool -> Garbage Collection -> Referenzzählung gibt keinen Sinn -> Automatic Reference Counting gibt keinen Sinn.

    Also: ARC braucht Autorelease Pools. Mag dir komisch erscheinen, ist aber so. Lies die Dokumentation.

    Bei Core Foundation sind die Regeln anders, da gibt es kein Deferred Release, keinen Autorelease Pool und kein Automatic Reference Counting.