Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[CORE] Performance bei Klassenladen

2 views
Skip to first unread message

Michael Doswald

unread,
Aug 31, 2004, 5:37:18 AM8/31/04
to
Hallo,

Folgendes Szenario:
Ich arbeite an einem mittelgrossen Project (ca. 1000 Klassen). Das
ganze ist als Applet realisiert und besteht hauptsächlich aus
GUI-Masken (Swing).

Das Applet ist in verschiedene jar-files aufgeteilt (main, base und
ein jar für jedes Modul). Beim Start befindet sich nur das main.jar im
Classpath. Wenn der User ein Modul öffnet, dann wird das base.jar und
das entsprechende Modul-jar heruntergeladen und es wird ein neuer
ClassLoader instanziert, dem diese beiden jar-files bekannt sind.

Wenn der User nun ein zweites Modul öffnet, dann erstellt das
Hauptapplet wieder einen neuen ClassLoader. D.h. die Klassen im
base.jar werden für jedes Modul neu geladen (da sie ja nur dem
ClassLoader des jeweiligen Moduls bekannt sind).

Das Problem ist, dass in diesem jar sehr viele GUI-Klassen sind die
von Swing-Components abgeleitet sind und von allen Modulen verwendet
werden. Nun ist es so dass ich zum laden einer GUI-Maske (z.B. 6 Tabs
mit je ca. 40-50 Swing Components) bis zu 4 Sekunden brauche. Wenn ich
die Maske dann schliesse und wieder öffnet, dauert es nur noch etwa
100-200 ms. Das ist in jedem Modul so.


Meine eigentliche Frage:

Kann man diesen Zeitunterschied alleine dadurch erklären, dass die
Klassen beim ersten mal geladen werden müssen und der Hotspot den code
optimiert/compiliert beim ersten Aufruf?

Wenn ja, wäre ein grosser Performance-Vorteil zu erwarten wenn ich die
GUI-Klassen vom base.jar in mein main.jar verschieben würde, damit sie
nur einmal geladen werden?


mfg
Michael Doswald

Michael Borgwardt

unread,
Aug 31, 2004, 5:47:17 AM8/31/04
to
Michael Doswald wrote:
> Kann man diesen Zeitunterschied alleine dadurch erklären, dass die
> Klassen beim ersten mal geladen werden müssen und der Hotspot den code
> optimiert/compiliert beim ersten Aufruf?

Die Hotspot-Optimierung dürfte da kaum relevant sein, das Laden
der Klassen jedoch schon.

> Wenn ja, wäre ein grosser Performance-Vorteil zu erwarten wenn ich die
> GUI-Klassen vom base.jar in mein main.jar verschieben würde, damit sie
> nur einmal geladen werden?

Probier's aus, das kostet doch weniger Zeit als das Posting hier...

Stefan Matthias Aust

unread,
Aug 31, 2004, 5:54:23 AM8/31/04
to
Michael Doswald schrieb:

> Wenn der User nun ein zweites Modul öffnet, dann erstellt das
> Hauptapplet wieder einen neuen ClassLoader. D.h. die Klassen im
> base.jar werden für jedes Modul neu geladen (da sie ja nur dem
> ClassLoader des jeweiligen Moduls bekannt sind).

Jedes Mal? Umgehst du so nicht das caching des Java-Plug-ins?

> Das Problem ist, dass in diesem jar sehr viele GUI-Klassen sind die
> von Swing-Components abgeleitet sind und von allen Modulen verwendet
> werden. Nun ist es so dass ich zum laden einer GUI-Maske (z.B. 6 Tabs
> mit je ca. 40-50 Swing Components) bis zu 4 Sekunden brauche. Wenn ich
> die Maske dann schliesse und wieder öffnet, dauert es nur noch etwa
> 100-200 ms. Das ist in jedem Modul so.

Punkt 1: Ist es das Laden der Klassen oder das Laden von Bildern, was
ebenfalls nicht zu vernachlässigen ist? Ein ImageIcon ist zwar bequem,
bremst aber das GUI aus.

Punkt 2: Ist es das Laden der Klassen oder das Initialisieren des GUIs?

Punkt 3: Ist es das Laden via HTTP, das laden via ClassLoader, das
Nachladen von Swing, getriggert durch die referenzierten Klassen oder
irgendwelche statischen Initializer in deinem Code?

Was passiert im Applet-Viewer?

Was passiert, wenn die jars lokal liegen und so HTTP keine Rolle mehr
spielt?

> Kann man diesen Zeitunterschied alleine dadurch erklären, dass die
> Klassen beim ersten mal geladen werden müssen und der Hotspot den code
> optimiert/compiliert beim ersten Aufruf?

Hotspot kompiliert nicht beim ersten Aufruf sondern erst später wenn der
Code häufiger durchlaufen wird gerade um dieses Problem zu umgehen.
Java ist aber verpflichtet, jeden Code zu verifizieren und das dauert lange.

> Wenn ja, wäre ein grosser Performance-Vorteil zu erwarten wenn ich die
> GUI-Klassen vom base.jar in mein main.jar verschieben würde, damit sie
> nur einmal geladen werden?

Probier's.


bye
--
Stefan Matthias Aust // "Zweifel sind der Ansporn des Denkens..." -U

Michael Doswald

unread,
Aug 31, 2004, 10:42:36 AM8/31/04
to
Michael Borgwardt <bra...@brazils-animeland.de> wrote in message
> > Wenn ja, w re ein grosser Performance-Vorteil zu erwarten wenn ich die
> > GUI-Klassen vom base.jar in mein main.jar verschieben w rde, damit sie

> > nur einmal geladen werden?
>
> Probier's aus, das kostet doch weniger Zeit als das Posting hier...

Leider ist das nicht so einfach. Das Problem ist, dass das Design
"vorsätzlich" so gewählt wurde (das Programm ist schon älter, ich war
nicht seit Anfang an dabei und somit nicht für die Architektur
verantwortlich :)

Es gibt Klassen im base.jar die statische Variablen beinhalten (z.B.
den Window-Manager). Wenn ich für jedes Modul einen eigenen
ClassLoader habe, dann existieren diese statischen Daten für jedes
Modul separat. So muss ich mich nicht darum kümmern in welchem Modul
ich gerade bin, wenn ich WindowManager.getInstance() aufrufe bekomme
ich immer gleich das Window von diesem Modul.

Jetzt ist es so dass die Klassen aber sehr "verknüpft" sind. D.h. um
zu testen ob meine Vermutung stimmt, müsste ich das halbe Applet
umschreiben. Darum wollte ich zuerst hier fragen ob sich der Aufwand
überhaupt lohnt.

Syren Baran

unread,
Aug 31, 2004, 10:45:33 AM8/31/04
to
Michael Doswald wrote:
> Hallo,

> Wenn der User nun ein zweites Modul öffnet, dann erstellt das
> Hauptapplet wieder einen neuen ClassLoader. D.h. die Klassen im
> base.jar werden für jedes Modul neu geladen (da sie ja nur dem
> ClassLoader des jeweiligen Moduls bekannt sind).

Sicher?
Wenn du den alten ClassLoader nicht "wegschmeist" werden die Klassen
nicht jedesmal neu geladen, da sie noch bekannt sind. Also, zumindest
wenn du von URLClassLoader ableitest (fragt immer den parent ClassLoader
voher) und das ganze nicht händisch mit defineClass machst.

> Meine eigentliche Frage:
>
> Kann man diesen Zeitunterschied alleine dadurch erklären, dass die
> Klassen beim ersten mal geladen werden müssen und der Hotspot den code
> optimiert/compiliert beim ersten Aufruf?
>
> Wenn ja, wäre ein grosser Performance-Vorteil zu erwarten wenn ich die
> GUI-Klassen vom base.jar in mein main.jar verschieben würde, damit sie
> nur einmal geladen werden?

Vermute eher, dass der alte ClassLoader noch existert oder dein Browser
die JAR-Dateien cached.
> mfg
> Michael Doswald

Gruss,
Syren

Michael Doswald

unread,
Aug 31, 2004, 10:55:24 AM8/31/04
to
Stefan Matthias Aust <nob...@3plus4.de> wrote in message news:<2pj06gF...@uni-berlin.de>...

> Michael Doswald schrieb:
>
> > Wenn der User nun ein zweites Modul öffnet, dann erstellt das
> > Hauptapplet wieder einen neuen ClassLoader. D.h. die Klassen im
> > base.jar werden für jedes Modul neu geladen (da sie ja nur dem
> > ClassLoader des jeweiligen Moduls bekannt sind).
>
> Jedes Mal? Umgehst du so nicht das caching des Java-Plug-ins?

Genau, das ist ja glaube ich auch das Performance issue hier :)


> Punkt 1: Ist es das Laden der Klassen oder das Laden von Bildern, was
> ebenfalls nicht zu vernachlässigen ist? Ein ImageIcon ist zwar bequem,
> bremst aber das GUI aus.

Es werden so gut wie keine Bilder geladen, höchstens ein paar wenige
Icons.
Ich glaube nicht dass es daran liegt.


> Punkt 2: Ist es das Laden der Klassen oder das Initialisieren des GUIs?

Ich nehme an, wie ich bereits gesagt habe, dass es das Laden der
Klassen ist, da ja beim mehrmaligen Öffnen des GUIs die
initialisierung _sehr_ viel schneller geht.


> Punkt 3: Ist es das Laden via HTTP, das laden via ClassLoader, das
> Nachladen von Swing, getriggert durch die referenzierten Klassen oder
> irgendwelche statischen Initializer in deinem Code?

Das Laden via HTTP sollte kein Problem darstellen. Die jar-files
werden nur einmal vom Server geladen, solange die Version sich nicht
verändert hat. Danach sind sie lokal gespeichert und werden von da
gelesen.


> Was passiert im Applet-Viewer?

Wenn ich alle Klassen gleich zu begin im classpath habe (also von der
IDE aus starte, dann wir nämlich der code mit dem Classloader etc.
übergangen) dann ist die erste Maske die ich öffne auch langsam,
allerdings werden alle weiteren Masken recht schnell initialisiert
(auch wenn ich Masken in einem anderen Modul öffne).


> Probier's.

Wie gesagt, das ist nicht so einfach (siehe obiges Posting)


mfg
Michael Doswald

Michael Borgwardt

unread,
Sep 1, 2004, 3:09:03 AM9/1/04
to
little...@gmx.net (Michael Doswald) wrote in message news:<99f95f8f.04083...@posting.google.com>...

> > Probier's aus, das kostet doch weniger Zeit als das Posting hier...
>
> Leider ist das nicht so einfach. Das Problem ist, dass das Design
> "vorsätzlich" so gewählt wurde (das Programm ist schon älter, ich war
> nicht seit Anfang an dabei und somit nicht für die Architektur
> verantwortlich :)
>
> Es gibt Klassen im base.jar die statische Variablen beinhalten (z.B.
> den Window-Manager).

Autsch, mein Beileid.

> Wenn ich für jedes Modul einen eigenen
> ClassLoader habe, dann existieren diese statischen Daten für jedes
> Modul separat. So muss ich mich nicht darum kümmern in welchem Modul
> ich gerade bin, wenn ich WindowManager.getInstance() aufrufe bekomme
> ich immer gleich das Window von diesem Modul.

Also ein klassischer Singleton-Mißbrauch. Wobei, wenn es nur das ist, das
läßt sich noch mit einigermaßen begrenztem Aufwand machen, jedenfalls in
einer guten IDE. Einfach getInstance() in getInstance(String modulName)
umschreiben (über 'ne HashMap), die IDE zeigt alle Aufrufe der jetzt nicht
mehr existenten parameterlosen Methode an, die man dann entsprechend ändert.

Natürlich kann es beliebig viel komplizierter sein.

0 new messages