Titanium Mobile – Vermeiden und Aufspüren von Memory Leaks in Android und iOS – Teil 1

Avatar von Thomas Steur

Spätestens wenn Ihre Mobile App größer oder komplizierter wird, sollten Sie einen Blick auf den Speicherverbrauch werfen. Ansonsten drohen Abstürze und verärgerte Benutzer. In diesem Teil geht es darum, wie Sie Memory Leaks vermeiden. Im zweiten Teil wird dann erläutert, wie Sie Memory Leaks in iOS und Android aufspüren.

Wie Sie Memory Leaks vermeiden

Viele gehen bei Titanium davon aus, dass Speicher automatisch freigegeben wird, sobald ein Fenster geschlossen oder ein UI-Widget entfernt wird. Dies ist jedoch nur der Fall, wenn keine JavaScript Referenzen auf das jeweilige Titanium Objekt vorhanden sind.

Titanium ermöglicht Ihnen Mobile Apps in JavaScript zu schreiben, die nativ ausgeführt werden. Titanium ist also eine Schicht zwischen JavaScript und der nativen Umgebung. Wenn Sie ein beliebiges Titanium Objekt erstellen, zum Beispiel ein Fenster, wird einerseits ein JavaScript-Objekt angelegt, andererseits ein natives Proxy-Objekt.

Das native Objekt gibt Titanium erst dann frei, wenn das entsprechende JavaScript-Objekt vom JavaScript Garbage Collector bereinigt wurde. Das heisst: In Titanium wird Speicher nur dann freigegeben, wenn ein UI-Widget nicht mehr angezeigt wird und wenn in JavaScript keine Variablen / Properties / Objekte mehr existieren, die darauf referenzieren. Setzen Sie daher Variablen auf "null", sobald Sie Referenzen hierauf nicht mehr benötigen.

Beispiel:

var win  = Ti.UI.currentWindow;
var view = Ti.UI.createView({backgroundColor: 'red'});
win.add(view);
win.open();
win.remove(view);
// Die View wird zwar nicht mehr angezeigt, aber es existiert noch eine Referenz 
// darauf. Die View befindet sich daher weiterhin im Speicher. Sie könnten 
// schließlich die View erneut dem Fenster hinzufügen wollen.
view     = null;
// Erst jetzt kann der Garbage Collector zuschlagen.

Wenn Sie ein übergeordnetes UI-Widget entfernen und auf "null" setzen, zum Beispiel ein Fenster, werden nur die enthaltenen UI-Widgets freigegeben, auf die keine Referenzen mehr existieren.

Beispiel:

var win   = Ti.UI.currentWindow;
var image = Ti.UI.createImageView({image: 'datei.png'});
win.add(image);

var label = Ti.UI.createLabel({text: 'Das ist ein Label'});
win.add(label);
label     = null;
// Auf den Label existiert nun keine Referenz mehr.

win.open();
// ...
win.close();
// Das Fenster ist noch im Speicher da erneut die Methode win.open() aufgerufen 
// werden könnte. Daher ist auch der Label und das Bild noch im Speicher.

win   = null;
// Es besteht keine Referenz mehr auf das Fenster, der Garbage Collector kann 
// zuschlagen. Da auf den Label ebenfalls keine Referenz mehr existiert, wird 
// auch dieser freigegeben. Auf das Bild existiert noch eine Referenz, daher 
// kann dieses Objekt nicht aufgeräumt werden. Schließlich könnten Sie das Bild 
// zum Beispiel noch in einem anderen Fenster verwenden wollen.

image = null;
// Erst jetzt kann auch das Bild freigegeben werden.

Event-Listener

Speziell globale Event-Listener – dazu gehören u.a. Ti.App, Ti.Geolocation und Ti.Gesture – sollten Sie mit Vorsicht verwenden. Globale Event-Listener existieren solange, bis die App beendet wird. Dadurch kann es vorkommen, dass Referenzen nicht frei gegeben werden. Entfernen Sie daher Event-Listener, sobald Sie diese nicht mehr benötigen.

Beispiel:

var site = null;
var onSiteChange = function (event) {
    site = event.site;
};

Ti.App.addEventListener('siteChange', onSiteChange);
// Die Referenz wird solange existieren, bis die App beendet wird. Es sei denn, 
// der Event-Listener wird zu einem späteren Zeitpunkt wieder entfernt.

Ti.UI.currentWindow.addEventListener('close', function() {
    // Der Event-Listener wird entfernt, sobald das aktuelle Fenster geschlossen 
    // wird.
    Ti.App.removeEventListener('siteChange', onSiteChange);
});

Den Event-Listener "Ti.App" benötigen Sie nur dann, wenn Sie ein Event an mindestens ein anderes Titanium Fenster bzw. einen anderen Kontext senden möchten. Ist dies nicht der Fall, können Sie zum Beispiel mit "Ti.UI.Window" Events arbeiten.

Aufräumen

Es wird Ihnen möglicherweise passieren, dass Sie Titanium Objekte nicht direkt auf "null" setzen können. Sie sollten daher zu einem späteren Zeitpunkt, wenn Sie die Referenzen mit Sicherheit nicht mehr benötigen, Aufräumarbeiten vornehmen.

Beispiel:

var view   = Ti.UI.createView({backgroundColor: 'red'});
var button = Ti.UI.createButton({title: 'Ausblenden'});
button.addEventListener('click', function () {
    view.hide();
);

Ti.UI.currentWindow.add(view);
Ti.UI.currentWindow.add(button);
button = null;
// Die Variable 'view' kann nicht auf 'null' gesetzt werden, da im Click 
// Event-Listener noch eine Referenz darauf benötigt wird.

Ti.UI.currentWindow.addEventListener('close', function () {
    view = null;
    // Zu diesem Zeitpunkt wird die Variable 'view' nicht mehr benötigt. Der 
    // Garbage Collector kann die 'view' jetzt aufräumen.
});

Klassen

In JavaScript haben Sie verschiedene Möglichkeiten, um Objekte zu erstellen. Je nachdem wie Sie Objekte erstellen, belegen diese mehr oder weniger Speicher. Spätestens wenn Sie mit vielen größeren Objekten zu tun haben, macht sich dieses bemerkbar. Es gibt dabei allerdings nicht die perfekte Vorgehensweise. Alle Varianten haben unterschiedliche Vor- und Nachteile.

Variante 1:

function window (url) {
    this.url = url;
    this.cleanup = function () {
        // ...
    }
}

Variante 2:

function window (url) {
    this.url = url;
}

window.prototype.cleanup = function () {
    // ...
}

Wenn Sie bei Variante 1 ein "window" Objekt erstellen, würde in jedem erstellten Objekt die Methode "cleanup" erstellt werden. Während dessen würde bei Variante 2 die Methode für alle "window" Objekte nur ein einziges Mal existieren. Die Variante 2 benötigt weniger Speicher und ist zudem schneller. Allerdings hat Variante 2 den Nachteil, dass Sie keine privaten Variablen oder Closures verwenden können. Mehr Informationen zu diesem Thema und weitere Varianten finden Sie zum Beispiel in dieser StackOverflow Diskussion. Wichtig ist, dass Sie wissen, dass es verschiedene Techniken hierfür gibt und deren Vor- und Nachteile kennen.

Avatar von Thomas Steur

Kommentare

Eine Antwort zu „Titanium Mobile – Vermeiden und Aufspüren von Memory Leaks in Android und iOS – Teil 1“

  1. In Teil 1 wurde erklärt, wie Sie Memory Leaks in Titanium Mobile vermeiden. Diese Fortsetzung erklärt das Aufspüren von Memory Leaks. iOS: Memory Leaks finden In iOS lässt sich relativ einfach heraus finden, ob Memory Leaks existieren. Gehen Sie dazu

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.