Statische Referenzen werden gelöscht--muss Android entladen von Klassen zur Laufzeit, wenn nicht verwendete?

Ich habe eine spezifische Frage zu, wie die zum laden von Klassen /garbage collection arbeitet in Android. Wir haben stolperte über dieses Problem ein paar mal jetzt, und soweit ich sagen kann, Android verhält sich hier anders aus als eine gewöhnliche JVM.

Das problem ist dieses: Wir sind derzeit versucht zu reduzieren auf die singleton-Klassen in der app zu Gunsten einer einzigen root-factory-singleton-die einzige Aufgabe ist die Verwaltung von anderen manager-Klassen. Eine top-level-manager, wenn man so will. Dies macht es für uns nicht leicht zu ersetzen-Implementierungen in den tests, ohne sich für eine vollständige DI Lösung, da alle Aktivitäten und Dienstleistungen Anteil die gleiche Referenz auf das root-Fabrik.

Hier ist, wie es aussieht:

public class RootFactory {

    private static volatile RootFactory instance;

    @SuppressWarnings("unused")
    private Context context; //I'd like to keep this for now

    private volatile LanguageSupport languageSupport;
    private volatile Preferences preferences;
    private volatile LoginManager loginManager;
    private volatile TaskManager taskManager;
    private volatile PositionProvider positionManager;
    private volatile SimpleDataStorage simpleDataStorage;

    public static RootFactory initialize(Context context) {
        instance = new RootFactory(context);
        return instance;
    }

    private RootFactory(Context context) {
        this.context = context;
    }

    public static RootFactory getInstance() {
        return instance;
    }

    public LanguageSupport getLanguageSupport() {
        return languageSupport;
    }

    public void setLanguageSupport(LanguageSupport languageSupport) {
        this.languageSupport = languageSupport;
    }

    //...
}

initialize einmal aufgerufen wird, in Application.onCreate, d.h. vor jede Tätigkeit oder Dienst gestartet wird. Nun, hier ist das problem: die getInstance Methode kommt manchmal zurück, wie null - auch wenn Sie angerufen werden, auf dem gleichen thread! Das klingt wie es ist nicht eine Sichtbarkeit problem, sondern die statische singleton-Referenz halten auf Klassenebene scheint tatsächlich gelöscht wurden durch den garbage collector. Vielleicht habe ich voreilige Schlüsse zu ziehen hier, aber konnte dies sein, weil die Android-garbage-collector-oder class-loading-Mechanismus kann tatsächlich entladen Klassen, wenn der Speicher wird knapp, in dem Fall die einzige Referenz zur singleton-Instanz zu gehen? Ich bin nicht wirklich tief in der Java-memory-Modell, aber ich nehme an, dass sollte nicht passieren, sonst wird dieser gemeinsame Weg für die Umsetzung von singletons nicht funktionieren würde auf jede JVM, richtig?

Irgendeine Idee, warum dies geschieht genau?

PS: man kann es umgehen das, indem es "Globale" Verweise auf die einzige Instanz der Anwendung statt. Das bewiesen hat, zuverlässig zu sein, wenn man halten muss, auf Objekt, um über die gesamte Lebensdauer einer app.

UPDATE

Anscheinend ist mein Einsatz flüchtiger hier für Verwirrung. Meine Absicht war es, sicherzustellen, dass der statische Verweis der aktuelle Zustand ist immer sichtbar für alle threads zugreifen. Ich muss das tun, weil ich sowohl schreiben und Lesen, das referenzieren von mehr als einem thread: In einer normalen app läuft nur im Hauptanwendungs-thread, aber in einer Instrumentierung Testlauf, bei denen Objekte ersetzt zu bekommen mit mocks, ich Schreibe es aus der instrumentation-Gewinde-und Lesen Sie es auf dem UI-thread. Ich könnte auch synchronisiert den Anruf zu getInstance, aber das ist teurer, da es erfordert, fordern Sie ein Objekt sperren. Sehen Was ist eine effiziente Methode zum implementieren eines singleton-pattern in Java? für eine detailliertere Diskussion um dieses.

  • Ich habe gesehen, diese Art von Verhalten zu, während der Ausführung von Instrumentierung. Ich wäre daran interessiert zu sehen, eine Antwort. Aber danke für den Hinweis über volatile; ich werde haben Sie einen Blick auf, die.
  • "initialize aufgerufen wird, sobald in Anwendung.onCreate, also vor jeder Aktivität oder der Dienst wird gestartet" --> alle refs auf dieser ?
  • Ein sinnvoller Schritt wäre, das logging initialize() und getInstance(), und bestätigen, dass das letztere wird nie aufgerufen, bevor die ehemaligen. Auch, fügen Sie die Protokollierung, um alles, was updates instance. Der garbage collector nicht NULL Felder aus, und auch wenn Android hat entladen Klassen würde es nur tun, wenn alle Klassen geladen, die von den gleichen ClassLoader konnte verworfen werden. Beachten Sie, dass alle statischen Felder sind im wesentlichen "reset", wenn die app getötet wird, und durch das system wiederholt gestartet.
  • Hatten Sie schon einmal unten auf dieser? FYI: ein Beispiel für eine statische volatil präsentiert sich in Effektive Java-2. Auflage, Seite 262, Ziffer 66. Wie bereits erwähnt, flüchtig ist erforderlich, um sicherzustellen, dass das aktuellste Wert der Instanz ist sichtbar für alle threads. Obwohl, kann es sich lohnen, mit einem enum oder ein anderes Synchronisations-Technik. So wie es da steht, nichts verhindert, dass clients, die gegen die angenommenen singleton-invariante, weil jeder Aufruf von initialize erstellen einer anderen Instanz.
InformationsquelleAutor Matthias | 2011-02-24
Schreibe einen Kommentar