PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Wann stirbt die Referenzierung oder woher weiss der Garbarge-Collector, dass ...



kit
27-03-2005, 12:04
... er aufräumen soll?

guten Morgen,

ehrlich gesagt, wird für mich Java immer unverständlicher. Das Speichermanagement wird für mich immer intransparenter. Bisher ging ich immer davon aus, dass ein Objekt solange initiiert ist und bleibt, bis entweder die letzte Referenz darauf geschlossen wird oder ein dispose() aufgerufen wird. Diese einfache Logik machte für mich auch Sinn, weil ja jedes Java-Programm mit einer Klasse startet. Sobald jedoch diese Klasse, welche alle anderen Objekte erzeugt und implizit auch darauf referenziert stirbt, müssen auch die erzeugten Objekte sterben.

Nun habe ich mir jedoch das Singleton-Pattern angesehen. Auf dieses wird nicht referenziert. Es erzeugt sich selbst und bleibt im Speicher. Nun stellt sich mir die Frage: wie lange eigentlich? Und woher weiss der GC, dass er das Singleton aufräumen darf?

Das Singleton ist für mich eine globales Objekt. Nur dachte ich, dass es genauso etwas in Java nicht gäbe? Jedenfalls verträgt sich das nicht mit meiner OO-Anschauung...

Viele Grüße
kit

peschmae
27-03-2005, 12:28
Der Garbage Collector räumt grundsätzlich auf wann der will - d.h. speziell dann wenn der Speicher knapp wird (JVMs von Sun haben per default einen 64 MB Heap-Limit) und das Programm gerade sonst nichts tut.

Grundsätzlich sollte dabei alles was nicht von irgendwo her referenziert wird abgeräumt werden dürfen. Wie das im Falle von einem Singleton aussieht weiss ich nicht, so Dinger habe ich bisher nur in C++ gesehen und dort sind die Probleme andere aber eigentlich ähnliche (wie zerstört man das Ding - wobei das kriegt man schon hin).
Hast du da mal ein Beispiel von nem einfachen Singleton in Java?

Hab gerade was gefunden: http://www.javacoffeebreak.com/articles/designpatterns/
hier hast du immer mindestens eine Referenz auf das Ding - eine statische in der SingletonObject-Klasse (plus eventuell von getSingletonObject() herausgegebene Referenzen). Also wird da nix abgeräumt durch die Garbage-Colleciton.

MfG Peschmä

fs111
27-03-2005, 13:57
Nun habe ich mir jedoch das Singleton-Pattern angesehen. Auf dieses wird nicht referenziert. Es erzeugt sich selbst und bleibt im Speicher. Nun stellt sich mir die Frage: wie lange eigentlich? Und woher weiss der GC, dass er das Singleton aufräumen darf?

Das Singleton ist für mich eine globales Objekt. Nur dachte ich, dass es genauso etwas in Java nicht gäbe? Jedenfalls verträgt sich das nicht mit meiner OO-Anschauung...

Viele Grüße
kit

Das Singleton wird gar nicht abgeräumt. Das soll es ja auch gerade nicht, denn seine Erzeugung ist teuer, und soll deshalb ja nur genau einmal geschehen. Das das Singleton seine einnzige Instanz selbst referenziert kann die GarbageCollection es nicht abräumen. Es gibt wohl einen Weg durch irgendwelche Events (habe nur davon gehört), auch dieses Objekt abzuräumen, das würde ja aber dem Sinn des Objektes widersprechen, denn man will es ja behalten bzw. schnell im Zugriff haben.

fs111

kit
27-03-2005, 18:19
Das Singleton wird gar nicht abgeräumt. Das soll es ja auch gerade nicht, denn seine Erzeugung ist teuer, und soll deshalb ja nur genau einmal geschehen. Das das Singleton seine einnzige Instanz selbst referenziert kann die GarbageCollection es nicht abräumen. Es gibt wohl einen Weg durch irgendwelche Events (habe nur davon gehört), auch dieses Objekt abzuräumen, das würde ja aber dem Sinn des Objektes widersprechen, denn man will es ja behalten bzw. schnell im Zugriff haben.

fs111

jo, genauso habe ich das verstanden. und genau das ist mein problem.
folgendes beispiel: ich habe eine Klasse A und diese ist mein Hauptanwendung. Nun wird durch A an einer Stelle eine Nebenanwendung B (z.B. ein Steuerelement zum Auswählen eines Datums) aufgerufen. B initialisiert aber eine Singleton-Klasse (z.B. einen GregorianCalendar oder einen DateFormater), der aber nicht mehr gebraucht wird, wenn B wieder geschlossen wird, nachdem das Datum ausgewähl wurde.
Heisst das nun, dass der Singleon die ganze Zeit bleibt, solange A läuft???? Ist das nicht wahnsinn? Was ist, wenn A ein GUI zur Steuerung ist und parktisch niemals stirbt? Bleiben dann alle Singletons von Steuerelementen, welche diese GUI anbietet geöffnet? Das hiese doch, dass nach einer Zeit die Summe aller Singletons im Speicher steht, selbst dann, wenn ich nur jeweils eines brauche???

also irgendwie gefällt mir dieses Konzept nicht. Gibt es auch Sprachen, die soetwas sauber lösen, also wirklich OO (ist Singleton aus meiner Sicht nicht) und mit Freigabe, sobald die Referenz auf ein Objekt weg ist?

viele Grüße
kit

peschmae
27-03-2005, 18:26
Es zwingt dich ja keiner Singletons zu verwenden wenn die nicht dem entsprechen was du willst. Es wäre ja nicht so dass das automatisch gutes Design wäre sowas zu verwenden nur weils einen Namen hat und im Design-Pattern Buch verewigt wurde...

Um mal jemanden zu zitieren:


Our group had a bad habit of using global data, so I did a study group on Singleton. The next thing I know Singletons appeared everywhere and none of the problems related to global data went away. The answer to the global data question is not, "Make it a Singleton." The answer is, "Why in the hell are you using global data?" Changing the name doesn't change the problem. In fact, it may make it worse because it gives you the opportunity to say, "Well I'm not doing that, I'm doing this" - even though this and that are the same thing. [Frieder Knauss]
http://home.earthlink.net/~huston2/dp/singleton.html

Wenn du das Objekt wieder loswerden willst ist die Frage wann. Wenn die Frage wann beantwortet ist dann machst du deinem Singleton-Klassendings halt noch eine Methode gibFreiZurGarbageCollection() hinzu die die static Referenz auf das Objekt auf null setzt - *dann* kann die GC auch zuschlagen weil es dann keine Referenz mehr auf das Objekt gibt.

MfG Peschmä

kit
27-03-2005, 19:33
Es zwingt dich ja keiner Singletons zu verwenden wenn die nicht dem entsprechen was du willst. Es wäre ja nicht so dass das automatisch gutes Design wäre sowas zu verwenden nur weils einen Namen hat und im Design-Pattern Buch verewigt wurde...


das ist klar, nur scheinen nicht wenige Klassen in Java selbst als Singleton implementiert zu sein, nämlich alle, welche nicht als Konstruktor, sondern als getInstance() aufgerufen werden (zumindest vermute ich das wegen der Analogie in der Nomenklatur).

wenn diese Vermutung stimmt, sind alle Klassen ala GregorianCalendar, Locale etc. ständig im Speicher, selbst wenn sie in der Anwendung nur einmal und kurz aufgerufen werden...

und es käme dann gar nicht darauf an, ob ich selbst ein Singleton implementieren möchte oder ob nicht...

weiss jemand, wie das in C# gelöst wurde? Ich werde mir wohl doch mal Ruby oder Haskel bzw. Eiffel anschauen.

Viele Grüße
kit

fs111
27-03-2005, 19:41
das ist klar, nur scheinen nicht wenige Klassen in Java selbst als Singleton implementiert zu sein, nämlich alle, welche nicht als Konstruktor, sondern als getInstance() aufgerufen werden (zumindest vermute ich das wegen der Analogie in der Nomenklatur).

wenn diese Vermutung stimmt, sind alle Klassen ala GregorianCalendar, Locale etc. ständig im Speicher, selbst wenn sie in der Anwendung nur einmal und kurz aufgerufen werden...

und es käme dann gar nicht darauf an, ob ich selbst ein Singleton implementieren möchte oder ob nicht...

weiss jemand, wie das in C# gelöst wurde? Ich werde mir wohl doch mal Ruby oder Haskel bzw. Eiffel anschauen.

Viele Grüße
kit

Die sind vermutlich ohnehin immer instanziiert, weil sie von verschiedenen anderen Klassen ohnehin benutzt werden, was bei Datums- und Zeitklassen für mich logisch erscheint.

fs111

Lin728
27-03-2005, 22:21
Außerdem kann man einen Singleton ja so implementieren, dass die eigentliche Instanz erst beim ersten getInstance() erzeugt wird, somit ists wieder "kostenlos"...

anda_skoa
28-03-2005, 16:02
eine Singleton-Klasse (z.B. einen GregorianCalendar oder einen DateFormater)

Bist du dir sicher daß es hier Singleton Instanzen sind?
Referenzen nach zwei Aufrufen verglichen, eventuell gar mit einem GC Lauf dawzischen?

Ciao,
_

kit
28-03-2005, 18:16
Bist du dir sicher daß es hier Singleton Instanzen sind?
Referenzen nach zwei Aufrufen verglichen, eventuell gar mit einem GC Lauf dawzischen?

Ciao,
_

hi,

nein, ich bin mir nicht sicher und habe nur von der Nomenklatur ausgehend vermutet.
Ich könnte allerdings mal in die Quellen des GCJ schauen...

Viele Grüße
kit

anda_skoa
29-03-2005, 15:15
nein, ich bin mir nicht sicher und habe nur von der Nomenklatur ausgehend vermutet.

Inwiefern schließt du da bei den als Beispielen genannten Factories (Calendar, Formatter) auf Singletons?

Ich würde da eher davon ausgehen, daß die Factory jedesmal eine neue Instanz erzeugt solange nicht explizit etwas anderes angegeben ist.



Ich könnte allerdings mal in die Quellen des GCJ schauen...


Ein einfaches Beispiel (Referenzenvergleich) zeigt zumindest bei meiner JVM das zwei Calendar Instanzen verschieden sind.
Was ansich auch sehr logisch ist, denn jede Instanz repräsentiert ja einen bestimmten Zeitpunkt.

Ciao,
_

RogerJFX
13-04-2005, 15:26
Also wenn ich so ein Ding schreibe, verlasse ich doch wohl wissentlich alle OOP-Gefilde.

Oder kürzer: was statisch ist, SOLL doch wohl die ganze Zeit im Speicher hängen. Und das will ich ja auch nicht anders in diesem Moment.

Das ist alles eine Frage der Architektur. Ich KANN Singletons schreiben, sollte es aber wirklich erst dann tun, wenn ich genau weiß, was ich mache.

Versuch doch mal, so ein Ding selbst zu entsorgen! Was soll dabei rauskommen?

z.B. (in vereinfachtem Kontext):

static object Feuerzeug = new String("foo");
static void disposeFeuerzeug() {
Feuerzeug = null;
System.gc(); // das würde er an sich schon machen
}

Jetzt beantworte man mir mal die eine Frage: warum, verdammt, ist Feuerzeug statisch? Sollte da jetzt von irgendwoher zugegriffen werden, wäre Feuerzeug nach disposeFeuerzeug() null? Unmöglich! Was, wenn der nächste kommt? NullPointer?

Meines Wissens geht das aber sogar. Man könnte also disposeFeuerzeug() schreiben. Und Feuerzeug wäre wohl wirklich null. Aber wer will sowas?

Kurz: was statisch ist, wird nach System.exit(0) automatisch entsorgt, und das ist gut so.

Und ein Singleton ist nix weiteres als eine statische Referenz auf die eigene (instantiierte) Klasse. Nicht zu entsorgen.

Cheers,

Roger

RogerJFX
13-04-2005, 15:34
delete kann nur aufräumen, was mit new erzeugt wurde. Statisches Zeug wird nie mit new instanziert. Ergo kann man es nicht aufräumen.

Das ist in C++ also nicht anders.

Nochmal cheers.

Lin728
13-04-2005, 16:32
Also wenn ich so ein Ding schreibe, verlasse ich doch wohl wissentlich alle OOP-Gefilde.

Oder kürzer: was statisch ist, SOLL doch wohl die ganze Zeit im Speicher hängen. Und das will ich ja auch nicht anders in diesem Moment.


Nein!
Was statisch ist, gehört zur Klasse selbst und nicht zum Object - wird die KLasse entladen verschwinden logischerweise auch die Objekte auf die die statischen Referenzen zeigen wieder.

So gesehen ists auch nicht Objektorientiert, weils ja nicht zum Objekt selbst gehört.

Ein Singleton ist der Versuch, Sachen die sich nicht besonders gut mit OOP realisiseren lassen, um einen OOP-Wrapper zu packen, um somit OOP-konformer zu werden.

RogerJFX
13-04-2005, 16:43
In dem Moment, in dem etwas statisch ist, klar, gehört es zur Klasse (brav, brav!), aber die Klasse ist dann nur noch eine Art Namespace.

Habe ich jetzt was übersehen, oder einfach nicht kapiert, worum es geht?

Lin728
13-04-2005, 17:23
Nöö, warum sollte die Klasse nur ne Art namespace sein?

Wird die Klasse vom GC entsorgt, sterben auch die Objekte auf die statische Referenzen dieser Klasse verweisen, solange es natürlich keine anderen gibt.

anda_skoa
13-04-2005, 22:28
delete kann nur aufräumen, was mit new erzeugt wurde. Statisches Zeug wird nie mit new instanziert.

Scherzkeks!
Seit wann kann man keine statische Pointervariable deklarieren?
(Bzw Referenz in Java)

Übrigend war das Problem in diesem Thread die irrtümliche Einstufung verschiedener Factories als Singleton.

Wie man durch einen einfachen Referenz Vergleich hätte feststellen können, erzeugt zb die Factory Methode Calendar.getInstance immer eine neue Instanz, was ja auch ganz logisch ist, denn eine Calendar Instanz beschreibt einen bestimmten Zeitpunkt und es wäre sonst nicht möglich mit mehr als einem Zeitpunktwert gleichzeitig zu arbeiten
Sehr unpraktischt :D

Das einzige Singleton in Java das mir gerade einfällt hat als Erzeuger Methode den selben Namen wie die Klasse nur eben mit get Prefix (java.awt.Toolkit)

Ciao,
_

kit
15-04-2005, 09:17
Scherzkeks!
Übrigend war das Problem in diesem Thread die irrtümliche Einstufung verschiedener Factories als Singleton.

Wie man durch einen einfachen Referenz Vergleich hätte feststellen können, erzeugt zb die Factory Methode Calendar.getInstance immer eine neue Instanz, was ja auch ganz logisch ist, denn eine Calendar Instanz beschreibt einen bestimmten Zeitpunkt und es wäre sonst nicht möglich mit mehr als einem Zeitpunktwert gleichzeitig zu arbeiten
Sehr unpraktischt :D


ja, tschuldigung. war mein Fehler. Für mich war Singleton wirklich neu. Ich habe vorher tatsächlich ein Objekt in der Hauptklasse erzeugt und dieses dann an alle aus der Hauptklasse gestarten Objekte als Parameter übergeben -- weil ich eben nur einen DateFormater und nur ein Ressource haben wollte...

viele Grüße
kit

nul
15-04-2005, 15:49
Java ist ein wenig eigens im Speichermamagement, da geb ich dir recht.
Du kannst beispielsweise den GC mit System.gc() (glaub ich wars) aufrufen, was dir aber nicht verspricht, dass er gleich ausgefuehrt wird. Es ist nor so was wie eine Empfehlung- "so, nun solltest du wieder was tun".

Intern hat jede Instanz einer klasse einen counter auf sich selbst, wird eine Referenz angelegt, wird der counter erhoeht, beim entfenrt eben umgekehrt. Das ist aber nicht ganz sicher. Refernzieren sich beispielsweise zwei Objekte selber und alle anderen Refernzen fallen weg ist der counter == 1 und die Instanzen werden nicht geloescht.

Deshalb baut die VM eine Baumstruktur an. Diesen Geht der GC durch und markiert alle elemente die er erreicht als gueltig, der rest wird geloescht. Da bei dieser Aktion aber groessere Loecher im Speicher auftreten (ineffizient) wird der gesamte Speicherblock dann in einen anderen Speicherblock geschrieben.

Nun wird der alte wieder freigegeben...

So in etwa laeuft das ab,

mfg nul

RogerJFX
16-04-2005, 08:05
Nöö, warum sollte die Klasse nur ne Art namespace sein?

Wird die Klasse vom GC entsorgt, sterben auch die Objekte auf die statische Referenzen dieser Klasse verweisen, solange es natürlich keine anderen gibt.

Seit wann wird eine Klasse vom GC entsorgt? Das ist höchstens eine Sache des dynamic ClassLoaders, was aber hat der mit dem GC zu tun, bzw. hat der ClassLoader jemals etwas entsorgt?

Das ist es doch gerade, was einen Singleton sinnvoll macht. Die statischen Pointer sind von anfang an vorhanden, und zeigen genau dann, wenn es etwas gibt, auf die Instanz, sonst auf null. Schreibe ich nun:

//...

static myClass instance; // = null;
static instance getInstance() {
if (instance == null) instance = new myClass();
return instance;
}

, bin ich sicher, daß der Konstruktor eben nur beim ersten Mal aufgerufen wird, und daß darüberhinaus nur eine einzige Instanz im Speicher klebt. Holla, das geht dann aber alles zügig.

Das Problem ist doch letztlich, wie ich diese Instanz (wenn es sie gibt), die schließlich private ist, je wieder loswerde. Manchmal gibt es ja eine Methode dispose() oder clear(), aber manchmal auch nicht.


Ich entschließe mich, einen Singleton zu schreiben, wenn ich

A. aus Preformancegründen ansich eine abstract class benötige mit lauter statischen Variablen/Methoden, meistens eine Klasse mit Basisfunktionalität, die immer wieder benötigt wird.

B. trotzdem eine gewisse Kapselung im Sinne der OOP durch Instanzierung erreichen will.

C. ich in keinem Falle mehr als eine Instanz der Klasse im Speicher gleichzeitig zulassen möchte (also ähnlich A.).

D. ich gegebenfalls den Speicher auch wieder freigeben möchte (betrifft logischerweise nur die Instanz-Variablen/Methoden).

E. ich sichergehen will, daß diese Überlegungen für alle nächsten Arbeitsschritte verbindlich gelten (deswegen letztlich der private-Konstruktor).


Übrigens ist Calendar nicht notwendigerweise ein Singleton. Der Konstruktor ist protected, nicht private. Es kann mich also niemand davon abhalten, eine Subclass zu schreiben, die ich entsprechend auch wieder loswerden kann.

Aber wie werde ich jemals das hier los (oder kann ich das nicht etwa schreiben, wo immer ich will?):

int day = java.util.Calendar.MONDAY;

:D

Cheers,

Roger

anda_skoa
16-04-2005, 16:21
Seit wann wird eine Klasse vom GC entsorgt?
Ich denke es war jedem klar das ceisserer Instanz gemeint hat.

Soweit durchblicken wir die Begriffe der OOP Welt schon um zu merken um was es im wesentlichen geht :rolleyes:



Übrigens ist Calendar nicht notwendigerweise ein Singleton.
Wie schon geklärt ist es auch keines, sondern die Annahme beruhte auf einem Mißverständis, d.h. kit's Annahme getInstance() wäre ein Hinweis auf Singleton, während getInstance bei den erwähnten Java Klassen eine Factory Method ist.

@kit: ist übrigens durchaus verständlich sowas zu denken, ich hab ja eigentlich auch versucht dich indirekt zur Erkenntnis zu führen, das man mit einem kleinen Test sowas leicht prüfen bzw widerlegen kann :)



Aber wie werde ich jemals das hier los (oder kann ich das nicht etwa schreiben, wo immer ich will?):

int day = java.util.Calendar.MONDAY;

Der Integer ist am Stack und wird vermutlich am Ende des Blockbereichs wieder freigegeben. Der Stack wird ja weiterbenutzt.

Ciao,
_