Push-Nachrichten von MacTechNews.de
Würden Sie gerne aktuelle Nachrichten aus der Apple-Welt direkt über Push-Nachrichten erhalten?
Forum>Entwickler>Speicherleck (CGImageRef)

Speicherleck (CGImageRef)

Christoph_M
Christoph_M30.04.1200:26
Hallo zusammen,

ich habe ein Problem und zwar läuft meine Cocoa Mac Applikation durch eine Schleife und verbraucht in jedem Durchgang zusätzliche 18MB Ram, was dazu führt dass auch 12GB irgendwann voll sind und dann das Paging los geht.
Der Code sieht so aus:

while([[startStopButton title] isEqualToString:@"Stop"]) {
            CGImageRef screenshot     = CGDisplayCreateImage(kCGDirectMainDisplay);
            NSBitmapImageRep *bitmapRep = [NSBitmapImageRep alloc];
            bitmapRep    = [bitmapRep initWithCGImage:screenshot];
            screenHeight = (int)bitmapRep.pixelsHigh;
            heightStep   = screenHeight/7; // 14 Schritte
            screenWidth  = (int)bitmapRep.pixelsWide;
            widthStep    = screenWidth/100*widthPercentage;
 ...
}           
Das Problem ist die Zeile:
CGImageRef screenshot     = CGDisplayCreateImage(kCGDirectMainDisplay);

Wenn ich diese aus der Schleife rausnehme und nur einmal ausführe und der Rest dann darauf zugreift bleibt die RAM-Belegung konstant bei ca. 80MB.
Nur was kann ich machen?
Wenn ich free(screenshot); mache, dann ist es entweder zu früh und es gibt Laufzeitfehler oder der Pointer existiert schon gar nicht mehr (Garage Collection ist aktiviert).

Ich hab bestimmt irgendwo einen Denkfehler drin, bin für jeden Stups in die richtige Richtung dankbar!

Grüße,
Christoph
0

Kommentare

Duck Dodgers30.04.1208:44
Hast du die Doku gelesen?

http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/Quartz_Services_Ref/Reference/reference.html
The caller is responsible for releasing the image created by calling CGImageRelease.


P.S: War gleich der zweite Link bei Google
0
Marcel Bresink30.04.1210:16
Garbage Collection funktioniert standardmäßig nur für reine Cocoa-Objective-C-Programmteile. Wenn man C-Schnittstellen verwendet (z.B. malloc oder CGImage-Funktionen), muss man sich bezüglich dieser Funktionen trotzdem "manuell" um die Speicherverwaltung kümmern.

Wenn in Apples API in einem Funktionsnamen die Bezeichnungen "Create" oder "Copy" auftauchen, wird immer Speicher reserviert, der vom Aufrufer wieder freigegeben werden muss. Dieser Speicher wird niemals mit "free" freigegeben, sondern immer nur mit einer ...Release-Funktion der entsprechenden Bibliothek, hier in diesem Fall also mit "CGImageRelease(screenshot)".

Für neue Programme sollte man übrigens Garbage Collection nicht mehr verwenden. GC wurde (zur optionalen Nutzung) in Mac OS X 10.5 eingeführt, hat sich aber mehr oder weniger als gescheitertes Experiment erwiesen und wird von Apple nicht mehr weiterentwickelt.
0
Christoph_M
Christoph_M30.04.1210:34
Danke euch beiden!
Habs direkt ausprobiert und es funktioniert!

Was mich allerdings wunder: ich erstelle das Screenshot doch jedes mal in die selbe Variable Screenshot. Müsste dadurch nicht der allokierte Speicherbereich überschrieben werden? Wenn nicht, wo landet dann das neue Screenshot?

Danke und Grüße,
Christoph
0
ExMacRabbitPro30.04.1211:28
Christoph_M
Danke euch beiden!
Habs direkt ausprobiert und es funktioniert!

Was mich allerdings wunder: ich erstelle das Screenshot doch jedes mal in die selbe Variable Screenshot. Müsste dadurch nicht der allokierte Speicherbereich überschrieben werden? Wenn nicht, wo landet dann das neue Screenshot?

Danke und Grüße,
Christoph

Diese Funktion: CGDisplayCreateImage fordert bei jedem Aufruf neuen Speicher von System an - unabhängig davon was zuvor geschah oder in welche Zeiger-Variable die zurückgelieferte Referenz gespeichert wird.
0
Marcel Bresink30.04.1212:17
Was mich allerdings wunder: ich erstelle das Screenshot doch jedes mal in die selbe Variable Screenshot.

Nicht wirklich. Die Variable screenshot ist vom Typ CGImageRef, also nur eine Referenz auf ein Bild, nicht das Bild selbst.

In Wirklichkeit ist das ein Zeiger auf eine Datenstruktur, die wiederum Zeiger auf Speicherbereiche enthält, die das Bild enthalten. Diese Speicherbereiche werden bei jedem "Create" immer wieder neu vom System abgebucht.

Nur wenn Garbage Collection auch für die C-Funktionen aktiv wäre, dann würde die Laufzeitumgebung erkennen, dass durch das Überschreiben der Referenz auch die referierte Datenstruktur freigegeben werden müsste. Wie gesagt wird Garbage Collection aber hier standardmäßig nicht verwendet.
0
MacMark
MacMark30.04.1213:51
Doku in Xcode und Dev pages Apple:
CGDisplayCreateImage
Returns an image containing the contents of the specified display.

CGImageRef CGDisplayCreateImage(
CGDirectDisplayID displayID
);
Parameters
display
The identifier of the display for which an image is being created.
Return Value
An image containing the contents of the specified display. If the display ID is invalid, the return value is NULL. The caller is responsible for releasing the image created by calling CGImageRelease.

Availability
Available in Mac OS X v10.6 and later.
Declared In
CGDirectDisplay.h

„@macmark_de“
0
Duck Dodgers30.04.1214:08
Lesen ist nicht gerade deine Stärke *sick*
0
Christoph_M
Christoph_M30.04.1215:58
Danke nochmal allen für die zahlreichen Antworten
Das Releasen funktioniert wunderbar, mir war nur nicht bewusst, dass sich der Speichbereich nach jedem Schleifendurchlauf verändert und damit das alte Bild im Speicher zurückbleibt. Danke Marcel für die Erklärung.
Duck Dodgers
*sick*
0
MacMark
MacMark30.04.1220:07
Dir fehlt elementares Grundlagenwissen zur Objective-C Programmierung. Kauf Dir ein Buch, sonst wird das nichts. Da steht sowas im Einführungskapitel, Homer.

Und Programmierer, die a) bei Problemen Google fragen, und b) eine Zeile ohne Kontext posten, kann man ebenso knicken. Ich schaue dich an, Duck.
„@macmark_de“
0

Kommentieren

Diese Diskussion ist bereits mehr als 3 Monate alt und kann daher nicht mehr kommentiert werden.