Visualisierung von Java

Werbung
Visualisierung von Java-Programmen!
27.08.2005
Seminar “Softwarevisualisierung”
Technische Universität Kaiserslautern
Betreuer: Dr. Andreas Kerren
Visualisierung von Java-Programmen
von
Samuel Strupp
Samuel Strupp (349495)!
1
Visualisierung von Java-Programmen!
27.08.2005
Inhaltsangabe
1. Einführung!
!
!
!
!
!
!
!
2. Programmvisualisierung - eine Definition!
!
2.1 Visualisierung! !
!
!
!
!
!
!
!
!
!
Seite 3
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
Seite 3
Seite 3
Seite 3
Seite 4
Seite 5
2.2 Softwarevisualisierung!!
!
!
!
2.2.1 Algorithmusvisualisierung!!
!
2.2.2 Programmvisualisierung! !
!
!
!
!
!
!
!
!
!
!
3. Was kann man visualisieren?! !
!
3.1 Visualisierungsideen! !
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
Seite 6
Seite 6
Seite 8
3.2 Probleme! !
!
!
!
!
!
!
4. JIVE! !
!
!
!
4.1 Über JIVE! !
!
!
!
!
!
!
!
!
!
!
!
!
!
!
4.2 Anforderungen an JIVE!
!
!
4.3 Lösungen in JIVE!
!
!
!
!
4.3.1 Verschiedene Ansichten! !
!
4.3.2 Kontursemantiken für Java!
4.4 Die Architektur von JIVE! !
!
4.5 Kurzer Ausblick in die Zukunft! !
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
Seite 18
Seite 18
Seite 18
Seite 18
Seite 20
Seite 24
!
!
!
!
!
!
!
5. JOVE!!
!
!
!
5.1 Über JOVE!!
!
!
!
!
!
!
!
!
!
!
5.2 Anforderungen an JOVE! !
5.3 Lösungen in JOVE! !
!
5.4 Die Architektur von JOVE! !
5.5 Kurzer Ausblick in die Zukunft!
Seite 10
Seite 10
Seite 10
Seite 11
Seite 11
Seite 13
Seite 15
Seite 17
6. Zusammenfassung und eigene Meinung!!
!
!
!
!
Seite 24
7. Literaturangaben! !
!
!
!
!
Seite 25
Samuel Strupp (349495)!
!
!
!
!
!
2
Visualisierung von Java-Programmen!
27.08.2005
1. Einführung
Dieses Dokument beschäftigt sich mit der Programmvisualisierung, also der grafischen
Darstellung von Programmzuständen und Programmabläufen. Zunächst wird der Begriff
der “Programmvisualisierung” erklärt, was darunter genau zu verstehen ist und wo der
Unterschied zu anderen Visualisierungen besteht. Im darauf folgenden Abschnitt werden
verschiedene Ideen der Programmvisualisierung besprochen und welche Probleme bei
der Visualisierung häufig auftreten. Danach werden die zwei Visualisierungswerkzeuge
JIVE und JOVE für Java-Programme vorgestellt. Das Interesse liegt dabei auf deren
Fähigkeiten die Programmabläufe und Programmstrukturen aufzunehmen und über
geeignete Grafiken sinnvoll darzustellen. Es wird also speziell die Visualisierung von
objekt-orientierter Software betrachtet, welche in der Sprache Java geschrieben wurde!
2. Programmvisualisierung - eine Definition
Zunächst wird der Begriff der „Visualisierung” erläutert, um danach über die Softwarevisualisierung auf die „Programmvisualisierung” und den Unterschied zur „Algorithmusvisualisierung” zu kommen.
2.1 Visualisierung
Eine Gemeinsamkeit aller Visualisierungen ist, Informationen unter einem bestimmten
Gesichtspunkt zu transformieren, um sie in einer geeigneten Sicht dem Anwender in einer
möglichst nützlichen Form zu präsentieren.
Die Transformation beinhaltet hierbei oft das geschickte Sichtbarmachen von nicht
sichtbaren Vorgängen, Ereignissen oder Zuständen. Im wesentlichen gibt es drei Arten
von Visualisierungen: die Visualisierung als Verschriftlichung, die Visualisierung als
Übersetzung ins Nonverbal-Optische und schließlich die Visualisierung als Illustration.
Das Ziel jeder Visualisierung ist die Bildung eines mentalen Modells.
2.2 Software-Visualisierung
Die Softwarevisualisierung hat das Ziel, die Funktionsweise einer Software, also deren
Arbeitsweise und Struktur, verständlich zu machen. Dies wird hauptsächlich über
Techniken der Typographie oder der Kinematographie zu erreichen versucht. Dabei
beschreibt die Typographie das Darstellen von Text. Die Kinematographie bezeichnet die
Verfahren zur Aufnahme und Wiedergabe von bewegten Bildern, bei denen man in
rascher Folge Bildreihen erzeugt und dann zur Betrachtung in analoger Weise wiedergibt.
Es werden also hauptsächlich Text und animierte Grafiken für die Visualisierungen von
Software benutzt.
Im wesentlichen gibt es zwei Arten von Softwarevisualisierung: die Algorithmenvisualisierung und die Programmvisualisierung [8] (siehe Abbildung 2.1).
Samuel Strupp (349495)!
3
Visualisierung von Java-Programmen!
27.08.2005
Software-Visualisierung
Algorithmen-Visualisierung
statische
AlgorithmenVisualisierung
dynamische
AlgorithmenVisualisierung
Programm-Visualisierung
statische
CodeVisualisierung
dynamische
CodeVisualisierung
statische
DatenVisualisierung
dynamische
DatenVisualisierung
Abbildung 2.1: Aufteilung der einzelnen Software-Visualisierungs-Gebiete
2.2.1 Algorithmusvisualisierung
Im wesentlichen findet man bei der Visualisierung von Algorithmen nur strukturelle
Ähnlichkeiten zwischen den Darstellungselementen und dem tatsächlich implementierten
Verfahren. Die Algorithmusvisualisierung ist also die Darstellung von Software auf einem
hohen Abstraktionsgrad. Das Teilgebiet lässt sich weiter in statische- und dynamische
Algorithmenvisualisierung untergliedern, wobei letzterer Visualisierungstyp auch als
Algorithmenanimation bezeichnet wird. Es gibt zum Beispiel eine Menge AlgorithmenAnimationen, welche die Arbeitsweise verschiedener Sortierverfahren mit Hilfe einfacher
animierter Darstellungen erläutern.
Ein einfaches Beispiel für eine statische Algorithmenvisualisierung ist ein
Programmablaufplan (Flussdiagramm), welcher in groben Zügen die Funktionsweise des
Programms bzw. des Algorithmus beschreibt. In der Regel werden nur wesentliche
Verfahrensschritte in statischer Form unter Verwendung einer grafischen Symbolik
dargestellt. Jeder Bezug auf eine konkrete Programmiersprache oder Implementierungsvariante wird dabei vermieden.
In Lehrbüchern findet dieser Visualisierungstyp oft Anwendung in statischer Form.
Werkzeuge, welche Algorithmusvisualisierungen dynamisch darstellen, sind meist
unflexibel im Bezug auf Verbesserungen oder Änderungen des Algorithmus, da dieser
meist fest im Werkzeug selber implementiert ist und nur selten über eine
Beschreibungssprache interpretiert wird. Die meisten Algorithmusvisualisierungen können
daher auch nur mit unterschiedlichen
Daten arbeiten die normalerweise
auch in einer be-stimmten Struktur
vorliegen müssen. Das Anwendungsgebiet dieses Visualisierungstyps
dient deswegen auch hauptsächlich
zum Verstehen des visualisierten
Algorithmus und wird somit hauptsächlich in der Lehre genutzt.
Abbildung 2.3: Beispiel einer Code-Visualisierung
Samuel Strupp (349495)!
4
Visualisierung von Java-Programmen!
27.08.2005
2.2.2 Programmvisualisierung
Der Unterschied zwischen der Programmvisualisierung und der Algorithmusvisualisierung
soll durch eine Definition des Begriffes Algorithmus verdeutlicht werden: Algorithmen sind
exakt formulierte Rechenvorschriften bzw. Vorgehensweisen, die auf Computern als
ausführbare Programme implementiert und auf diese Art für die Lösung von Aufgaben
angewandt werden können.
Ein Algorithmus besteht somit aus einer wohldefinierten endlichen Folge von elementaren
Rechenoperationen und Entscheidungen, um aus einer bestimmten Menge von
Eingabegrößen das gewünschte Resultat zu erzeugen.
Programme sind also nichts anderes als Implementierungsvarianten von bestimmten
Algorithmen. Bei der Programmvisualisierung geht es also um die Darstellung einer
konkreten Implementierung eines oder mehreren Algorithmen. Der wesentliche
Unterschied der beiden Visualisierungstypen liegt also im Abstraktionsgrad. Die
Programmvisualisierung hat in den meisten Fällen eine geringere Abstraktion, da sie ja die
konkrete Implementierung und nicht die Idee eines Algorithmus darstellen muss.
Die Programmvisualisierung kann man in zwei weitere Gruppen aufteilen, nämlich die
Codevisualisierung und die Datenvisualisierung. Diese Unterscheidung macht Sinn, da zur
Berechnung von Daten oft charakteristische Datenstrukturen im Programm verwendet
werden. Diese Strukturen kann man wiederum auf spezielle Weisen darstellen, um die
Funktionsweise einer solchen Berechnung bei der konkreten Implementierung noch
besser vermitteln zu können.
Es gibt viele Möglichkeiten, Daten intuitiver darzustellen. Zum Beispiel kann man ListenEinträge durch Rechtecke, deren Inhalt durch die entsprechenden Inhalte gefüllt sind,
darstellen. Die Verkettung der einzelnen Elemente wird dabei einfach durch Pfeile
gekennzeichnet (siehe Abbildung 2.2). Wird jetzt an der Liste etwas hinzugefügt, gelöscht
oder vertauscht, kann dieser Vorgang bei der dynamischen Datenvisualisierung durch
entsprechende Animationen, farbige Kennzeichnungen oder Symbole leicht verständlich
dargestellt werden.
3
6
8
2
12
5
Abbildung 2.2: Beispiel einer Daten-Visualisierung
Die Codevisualisierung kann zum Beispiel das Darstellen des entsprechenden
Programmcodes sein (siehe Abbildung 2.3). Das farbige Hervorheben des gerade aktiven
Programmteils kann als Code-Animation interpretiert werden. Aber auch die Darstellung
von Rekursionsbäumen bei rekursiven Verfahren oder die Darstellung eines SequenzDiagramms kann zu diesem Visualisierungstyp gehören. Oft ist es aber auch nicht
eindeutig, zu welchem Teilgebiet eine Visualisierung gehört, da sich die beiden Gebiete
bei solchen Darstellungen überschneiden. Zum Beispiel das Darstellen von
Klassenbeziehungen mit konkreten Instanzen und Werten kann sowohl der Code- als
auch der Datenvisualisierung zugeordnet werden, denn zum einen wird die Struktur des
Programms, also dessen Objekte und ihre Beziehungen, dargestellt und zum anderen
werden auch die einzelnen instanziierten Objekte mit deren Daten angezeigt. Ob die
Objekte jetzt spezielle Datenstrukturen repräsentieren oder Funktionsteile des Programms
sind, wird in solch einem Fall nicht unterschieden.
Samuel Strupp (349495)!
5
Visualisierung von Java-Programmen!
27.08.2005
In den folgenden Kapiteln werden hauptsächlich nur noch Programmvisualisierung von
Java-Programmen betrachtet und dabei anhand zweier Beispiele (Kapitel 4 und 5) vor
allem auf Eigenschaften wie Objekt-Orientierung und Threads eingegangen.
3. Was kann man visualisieren?
In diesem Kapitel werden verschiedene Ideen vorgestellt, welche Teile eines Programms
visuell repräsentiert werden können, was man dabei beachten sollte und was es für
Probleme bei der Visualisierung auftreten können.
3.1 Visualisierungsideen
Wie im vorhergehenden Kapitel beschrieben, gibt es bei der Programmvisualisierung zwei
unterschiedliche Arten von Visualisierungen, die Datenvisualisierung und die Codevisualisierung. Die Idee bei der Visualisierung ist es, die Struktur und Art des Programms
auf sinnvolle Weise grafisch darzustellen. Es ist z.B. möglich, jede Instanz eines Objektes
in Java einzig und allein durch das Füllen eines Kästchen in einem Gitterfeld zu
repräsentieren. Allerdings ist dies wohl eher wenig aussagekräftig, da man zwar eine
grafische Darstellung der instanziierten Objekte hat, aber aus dieser Darstellung nicht viel
Informationen entnehmen kann. Der Informationsgehalt einer Darstellung ist mit
ausschlaggebend für die Qualität einer Visualisierung. Der zweite wichtige Punkt ist die
Interpretierbarkeit der Visualisierung. Eine Visualisierung, die zwar viele wertvolle
Informationen beinhaltet, dies aber auf eine Weise darstellt, die vom Menschen gar nicht
oder nur sehr mühsam interpretiert werden kann, ist wertlos. Es ist also wichtig, sich
Gedanken darüber zu machen, was man darstellen kann, was sinnvoll ist, dargestellt zu
werden und vor allem, wie man es dann darstellt.
Es gibt viele Ideen für die Visualisierung von Programmen. Zunächst werden einige Ideen
betrachtet, welche eher der Codevisualisierung zuzuordnen sind:
Die Darstellung des Quellcodes ist sicher eine der einfachsten und geläufigsten
Programmvisualisierungen. Viele statische Programmvisualisierungen bauen ihre
Darstellungen des Programms anhand des Quellcodes auf (siehe Abbildung 2.3).
Die Darstellung von Objektstrukturen wird auch häufig
eingesetzt, um zum Beispiel
die Objektstruktur eines
Programms in UML wiederzugeben. Solche Diagramme
lassen sich relativ einfach
anhand des Quellcodes
erzeugen. Eine gut strukturierte und somit lesbare
Darstellung dieser Diagramme
wird allerdings um so Abbildung 3.1: Mögliche Visualisierung einer Objektstruktur als UML-Diagramm
komplizierter, je komplexer die
Objektstruktur wird (Beispiel siehe Abbildung 3.1).
Instanzen von Objekten können auch visualisiert werden. Dies ist bei der dynamischen
Codevisualisierung sehr sinnvoll, um das Verständnis für den Ablauf des aktuellen
Samuel Strupp (349495)!
6
Visualisierung von Java-Programmen!
27.08.2005
Programms zu erhöhen. Auch für das Debuggen von Programmen kann eine solche
Visualisierung gut genutzt werden. Instanzen können auf verschiedene Weisen dargestellt
werden, zum Beispiel durch einen einfachen Zähler der Instanzen eines bestimmten
Objekts oder wieder durch ein Diagramm, in dem durch Pfeile auch aktuelle
Objektverknüpfungen dargestellt werden können (siehe beispielsweise Abbildung 4.3 in
Kapitel 4).
Die bildliche Repräsentation von Methodenaufrufen
sind oft hilfreich, um die Kommunikation zwischen
Objekten nachvollziehen zu können. Eine mögliche
Visualisierung von Methodenaufrufen zwischen
verschiedenen Klassen und deren Instanzen ist in der
Abbildung 3.2 dargestellt. Sie stammt aus dem
Visualisierungswerkzeug „Jinsight“ [4] von Wim de Pauw
und weiteren. Ob dies jetzt eine sinnvolle Visualisierung
ist oder nicht, hängt immer vom Kontext sowie dem
Betrachter ab.
Den Ablauf eines Programms festzuhalten und gleichzeitig visuell darzustellen, erleichtert es enorm, die
Entstehung von Fehlern nachvollziehen zu können oder
den Ablauf im allgemeinen zu verstehen (Beispiel in
Abbildung 4.1). Oft werden hierfür Sequenzdiagramme
gezeichnet. Nicht nur der Ablauf des Programms selbst
kann interessant sein, sondern auch, was daraus
abgelesen werden kann. So kann das Visualisierungswerkzeug „JaVis” [3], das von Katharina Mehner an der
Universität von Paderborn entwickelt wurde, Deadlocks
im Programm erkennen und diese selbstverständlich
auch visualisieren (Abbildung 3.3).
Abbildung 3.2: Jinsight Visualisieung
von Methodenaufrufen (Linien)
Abbildung 3.3: Deadlock in JaVis
Eine recht interessante Sache ist die Darstellung von Threads. (Beispiel in Abbildung 4.1,
4.5 oder 5.1) Die Darstellung von Threads in einer Visualisierung ist sehr wichtig, da ohne
diese Komponente wichtige Teile, die zum Verständnis der Entstehung der Visualisierung
beitragen, fehlen. Man kann nicht nur Threads als Instanzen darstellen, sondern zum
Beispiel auch zu jedem Thread seine Ablaufgeschichte im Programm.
Eine weitere Möglichkeit, um Informationen über ein Programm zu bekommen, ist das
Visualisieren von Kommunikationen zwischen Betriebssystem und dem Programm.
Dies kann die Inanspruchnahme fremder Ressourcen durch das Programm verdeutlichen
und zudem den Grad der Abhängigkeit zur Laufzeit.
Ideen von Datenvisualisierungen:
Die Visualisierung von Daten, die in einem Programm genutzt werden bzw. vorhanden
sind, kann auch sehr nützlich sein. Man kann sich zum Beispiel vorstellen, dass man
Variablenwerte wie numerische Werte sowie Zeichen und Texte aber auch komplexe
Datenstrukturen wie Bilder, Videos und sogar Töne visualisiert, um den Ablauf eines
Programms, das mit diesen Daten arbeitet, besser verstehen zu können. Allerdings ist hier
die Frage, ob dies wirklich noch zur Programmvisualisierung gehört. Bei der Darstellung
von Variablen-Werten ist das weniger die Frage, aber bei der Darstellung von Bildern,
Samuel Strupp (349495)!
7
Visualisierung von Java-Programmen!
27.08.2005
Tönen und Videos wohl schon, da dies sehr spezielle Anforderungen sind und vielleicht
eher in den Bereich der Algorithmusvisualisierung fallen. Klar abgrenzen kann man dies
allerdings nicht, da auch spezialisierte Visualisierungen ihren Platz in allgemeineren
Visualisierungs-Umgebungen haben sollten.
Datenstrukturen können auch anhand des Quellcodes erkannt werden und somit
spezielle Darstellungsformen gewählt werden. Einfache Beispiele hierfür sind zum Beispiel
einfach und doppelt verkettete Listen (Abbildung 2.2), Bäume (Abbildung 4.3) oder auch
der Aufbau des Stacks.
Die exakte Darstellung des vom Programm zugeteilten Speichers und dessen Belegung
kann auch sehr Informativ sein, wenn Interesse an der Low-Level-Ebene des Programms
besteht. Allerdings wird diese Verteilung der Daten und die Speicherzuweisung zum
Großteil vom Betriebssystem erledigt und ist zudem bei heutigen Systemen sehr
dynamisch. Das hat zur Folge, dass die Informationen darüber erstens nur schwer
zugänglich sind und zweitens sich die Struktur nur schwer exakt abbilden lässt.
Eine Darstellung von Pufferzuständen oder Streamdaten kann, wenn es in geeigneter
Weise erfolgt, auch sehr zu dem Verständnis eines Programmablaufs dienen. Allerdings
sind auch hier wieder sehr spezielle Anforderungen an das Visualisierungs-Werkzeug zu
stellen, und die Menge an Daten eines Streams ist auch sehr schwer auf geeignete Weise
zu visualisieren.
Eine weitere Möglichkeit der Visualisierung liegt in
der Möglichkeit, externe Kommunikation, die über
das Betriebssystem hinaus geht, darzustellen. Zum
Beispiel könnte man Netzwerkverbindungen und
die damit verbundenen Datenflüsse visualisieren.
Das Programm Azureus [9] beinhaltet zum Beispiel
solch eine Visualisierung. Dabei handelt es sich um
ein File-Sharing-Programm auf Java-Basis,
welches es erlaubt, gleichzeitig von mehreren
Quellen eine Datei herunter zu laden. Die
Verbindungsstruktur ist in der Abbildung 3.4
repräsentiert.
Abbildung 3.4: Visualisierung von
Netzwerkverbindungen + Datenübertragungen in Azureus
Dies ist natürlich nur ein kleiner Ausschnitt von Ideen, welche Teile eines Programms
visualisiert werden können. Zudem ist die Vielfalt der Darstellungsmöglichkeiten enorm.
3.2 Probleme
Es gibt natürlich auch Probleme bei der Programmvisualisierung, welche nicht so einfach
zu lösen sind. In diesem Kapitel werden ein paar typische Probleme beschrieben.
1. Skalierbarkeit der Darstellungen
Viele Ansichten von Visualisierungen sind sehr detailliert und umfangreich. Das hat zur
Folge, dass bei der Visualisierung von sehr großen Systemen die Darstellungen sehr
komplex, umfangreich und für den Betrachter oft unüberschaubar werden. Es ist
beispielsweise wenig sinnvoll, einen Benutzer in einem Objektdiagramm, welches 20
Bildschirme füllen könnte, nach einem bestimmten Objekt suchen zu lassen. Dieser würde
eine solche Darstellung zudem sehr schnell als unbrauchbar deklarieren, wenn er die für
ihn interessanten Informationen nicht finden kann. Eine Lösung für dieses Problem könnte
Samuel Strupp (349495)!
8
Visualisierung von Java-Programmen!
27.08.2005
es sein, interessante Informationen zu filtern und nur diese darzustellen. Allerdings ist dies
nicht unbedingt immer realisierbar.
2. Geschwindigkeit
Visualisierungen benötigen oft viel Rechenleistung, um die Grafiken zu erzeugen. Aber
auch das Sammeln von Daten, welche für die Visualisierung benötigt werden, kann sehr
aufwändig sein. Externe Visualisierungs-Werkzeuge verlangsamen so den Ablauf eines
Programms oft erheblich. Das kann zur Folge haben, dass manche Programme nicht
korrekt funktionieren können, da sie eine gewisse Grundperformance benötigen, um ihre
Aufgaben korrekt durchführen zu können, z.B. Multimediaprogramme, die Ton- oder
Videodaten in Echtzeit verarbeiten müssen. Desweiteren können Programme, die stark
von Benutzereingaben abhängen, so extrem verlangsamt werden, dass eine sinnvolle
Nutzung nicht mehr gegeben ist. Bei der Visualisierung ist also immer darauf zu achten,
dass die benötigte Performance des zu visualisierenden Programms nicht zu sehr
eingeschränkt wird.
3. Spezialisierung
Die Spezialisierung von Programmvisualisierungssystemen auf bestimmte Plattformen
oder Programmiersprachen ist kein eigentliches Problem. Allerdings macht es deutlich,
dass es nicht einfach, wahrscheinlich sogar unmöglich ist, generelle VisualisierungsWerkzeuge für alle Programme zu erstellen, welche gleichzeitig sinnvolle Abstraktionen
des Programms darstellen. So kann ein Visualisierungs-Werkzeug, das auf das Darstellen
von objektorientierten Programmen spezialisiert ist, natürlich nicht viel mit einem rein
prozeduralem Programm anfangen.
4. Speicherplatzbedarf
Viele Visualisierungen basieren auf einer enormen Datenmenge, welche zum einen im
Speicher gehalten werden muss und auf die zum anderen möglichst schneller Zugriff
möglich sein muss. So kann z.B. bei einer Visualisierung, welche die komplette
Ablaufgeschichte eines Programms speichern soll, der Speicherbedarf riesig sein.
Deshalb sollte man immer darauf achten, dass nur benötigte Daten gespeichert werden
und dass eventuell redundante Daten optimiert gespeichert werden.
5. Implementierungsart
Es gibt natürlich zwei verschiedene Wege, um die Abläufe innerhalb eines Programms
darzustellen. Entweder das Programm liefert selbst Visualisierungen zu seinem Ablauf
oder die Daten werden von einem externen Programm bezogen und dann visualisiert. Die
erste Variante ist oft recht aufwändig, da sie beinhaltet, dass evtl. der komplette Quellcode
verändert werden muss, um Programmvisualisierungen zu implementieren. Das externe
Programm hingegen muss auf irgendeinem Wege an Daten über das Programm heran
kommen. Dies kann bei Java zum Beispiel über die JPDA (Java Plattform Debugger
Architektur) erfolgen.
6. Vergänglichkeit von Eingaben
Nicht alle Programme eigenen sich zur Visualisierung. Wie schon erwähnt, verlangsamen
Visualisierungen ein Programm manchmal sehr stark. Wenn dieses Programm, dann von
vergänglichen Daten, wie zum Beispiel einem Live-Video-Stream abhängt, diese Daten
aber nicht schnell genug verarbeiten kann, dann liefert die Visualisierung natürlich auch
keine Darstellung eines korrekten Ablauf des Programms. Zudem können viele
Situationen, die durch eine bestimmte Datenkonstellation erzeugt werden, nicht wieder
hergestellt werden, da genau diese Daten so nicht mehr zur Verfügung stehen. Dies
macht das Analysieren oder Vergleichen von Programmzuständen sehr schwierig bis
unmöglich, da die entsprechenden Situationen nicht reproduziert werden können.
Samuel Strupp (349495)!
9
Visualisierung von Java-Programmen!
27.08.2005
4. JIVE
4.1 Über JIVE
Der Name JIVE bedeutet „Java Interaktive Visualization Environment” also in Deutsch
etwa „interaktive Java Visualisierungs-Umgebung” [1]. Es gibt leider sehr viele
Programme, die den Namen „JIVE” tragen. Das JIVE, über welches hier gesprochen wird,
wurde von Paul Gestwicki und Bharat Jayaraman an der Universität von Buffalo
entwickelt. Es handelt sich dabei um ein Programmvisualisierungswerkzeug, welches
objektorientierte Java-Programme visualisiert.
Objektorientierte Programme unterscheiden sich von prozeduralen Programmen in zwei
wesentlichen Punkten: (1) Objekte sind nicht nur Datenstrukturen, sondern dienen auch
als Umgebungen, in denen Prozeduraufrufe stattfinden. (2) Objektorientierte Programme
verlangen die Nutzung von mehreren kleineren Methoden. Daraus resultieren dann
kompliziertere Wechselbeziehungen zwischen den Objekten. Das Ablaufverständnis eines
objektorientierten Java-Programms wird durch das zur Verfügung stellen von
Darstellungen der Objektstruktur sowie der Geschichte der Objektinteraktionen verbessert.
Obwohl diese Ansichten grundlegend für das Verständnis sind, gibt es laut Gestwicki und
Jayaraman kein Visualisierungssystem für objektorientierte Programme, welches diese
grundlegenden Kriterien realisiert. Die Visualisierungen aus JIVE sind generell anwendbar
auf alle objektorientierten Sprachen nicht nur auf Java im speziellen. Allerdings gibt es bei
jeder Sprache Komplikationen und kleine Nuancen, welche bewältigt werden müssen, so
auch bei Java.
4.2 Anforderungen an JIVE
Gestwicki und Jayaraman haben sieben Hauptanforderungen für ein System, das
Laufzeitzustände von Java visualisieren soll, aufgestellt:
1. Bildliche Darstellung von Objekten als Umgebungen. Es gibt bereits mehrere
Werkzeuge, welche die Methodenaufrufsequenz bildlich darstellen können, was wiederum
die Inspektion von objektinternen Details unterstützt. Allerdings stellen diese Werkzeuge
weder die gesamte Struktur des Objektes, noch die Methodenaufrufe in diesen Objekten
dar, und folglich fehlen wichtige Beziehungen in der Visualisierung.
2. Das zu Verfügung stellen von mehreren Ansichten der Laufzeitzustände. Der
momentane Ablaufzustand des Programms sollte auf verschiedenen Detailstufen
wahrnehmbar sein, um besser Vergleich durchführen zu können. Die Ansichten sollten
sowohl dem Anfänger zum Verstehen und Lernen dienen, wie auch einem Profi, der die
Visualisierungen zum Debuggen benutzt.
3. Festhalten der Ablaufgeschichte und Methodeninteraktion. Die Geschichte des
Programmablaufs sollte wahrnehmbar sein, indem Notationen wie Zeitsequenzdiagramme
oder Interaktionsdiagramme benutzt werden. Die Visualisierung der Programm-Geschichte
sollte interaktiv sein, sodass der Benutzer einen Punkt der Programmgeschichte
auswählen kann, den er betrachten will. Zum Beispiel sollte das Auswählen eines
Methodenaufrufes in einem Sequenzdiagramm das Visualisierungs-Werkzeug
veranlassen, den Laufzeitzustand, an dem die Methode aufgerufen wurde, darzustellen.
4. Unterstützen von Vorwärts- und Rückwärtsausführungen. Es sollte möglich sein,
interaktiv vorwärts und rückwärts durch den Programmablauf zu schreiten. Diese Fähigkeit
Samuel Strupp (349495)!
10
Visualisierung von Java-Programmen!
27.08.2005
ist besonders für das Debuggen wichtig, weil das Auftreten eines Fehlers normalerweise
erst nach einem gewissen Punkt erkannt wird. Auch sollte die Schrittgröße variabel sein,
(Statement-Ebene, Methoden-Ebene oder Breakpoints). Desweiteren sollten diese
Möglichkeiten auch bei Multithread-Programmen unterstützt werden.
5. Unterstützen von Abfragen des Laufzeitzustandes. Eine der wichtigsten Anforderungen
für das Programmdebuggen ist das Verständnis, wie sich die Variablenwerte ändern. Es
sollte möglich sein, den Laufzeitzustand nach Eigenschaften von Variablen abzufragen
(wurde Variable geändert oder hat die Variable einen bestimmten Wert angenommen?).
Aus dieser Anforderung resultiert eine abfragbare Datenbank von Laufzeitzuständen.
6. Erzeugen von klaren und lesbaren Zeichnungen. Die Visualisierungsumgebung sollte
automatisch Diagrammkomponenten anordnen, damit Objektstrukturen und
Methodenaufrufsequenzen dargestellt werden können. Individuelle Visualisierungen von
oft benutzten Typen, wie z.B. Arrays, Listen und Tabellen, sollten zur Verfügung stehen.
7. Die existierende Java Virtual Machine benutzen. Es ist wichtig, dass das
Visualisierungsystem auf der existierenden Java Virtual Machine (JVM) läuft und dass
keine extra Implementierung eines Java Interpreters
benötigt wird. Eine angepasste JVM-Implementierung
wäre sehr schwer auf dem aktuellen Stand zu halten.
Zusätzlich sollte es möglich sein, Programme mit einer
grafischen Benutzeroberfläche zu visualisieren, welche
mit Bibliotheken wie Swing oder AWT erstellt wurden.
4.3 Lösungen in JIVE
Ein grundlegendes Problem bei Visualisierungswerkzeugen ist die Frage, was eigentlich genau
visualisiert werden soll, und vor allem, wie es einfach
und verständlich dargestellt werden kann. JIVE bietet
dazu verschiedene Visualisierungen, welche die
verschiedenen Aspekte eines Programms darstellen
sollen. Diese verschiedenen Ansichten werden in 4.3.1
besprochen. Im Punkt 4.3.2 werden die Besonderheiten
von Java in Augenschein genommen, um die
Kontursemantiken dieser objektorientierten Sprache
visualisieren zu können.
4.3.1 Verschiedene Ansichten
Kompakte Ansichten (Compact Views)
Die kompakte Ansicht wird anhand eines gegebenen
rekursiv strukturierten binären Suchbaumes bildhaft
erläutert. Jeder Zweig des Baumes sei selbst wieder ein
Unterbaum. Abbildung 4.1 gibt eine mögliche
Visualisierung eines Zustandes der Programmausführung. Der obere Teil des Bildschirmfotos zeigt
eine Konturdiagrammvisualisierung der Objektstruktur.
Dies wird „kompakte Ansicht” genannt, da nicht alle
Details von jeder Kontur angezeigt werden. Die Abbildung 4.1: Kompakte Ansicht
und Sequenzdiagramm
Knotenpunkte des Baumes werden als dunkel umSamuel Strupp (349495)!
11
Visualisierung von Java-Programmen!
27.08.2005
randete Instanz-Konturen angezeigt. Jeder ist nach der Klasse benannt, in der er
instanziiert wurde (in diesem Fall DupTree) und ein Instanzenzähler wurde hinzugefügt,
um individuelle Objekte unterscheiden zu können. Es gibt eine statische Kontur für jede
Klasse, die von dem Java-System geladen wurde. Eine statische Kontur ist eingebettet in
die statische Kontur ihrer Superklasse, und da alle Klassen in Java Unterklassen von
java.lang.object sind, sind alle statischen Konturen eingebettet in die statische Kontur
von java.lang.object. Die Pfeile im Diagramm sind strukturelle Verknüpfungen, welche
anzeigen sollen, dass eine Referenz von einem Objekt zum anderen besteht. Diese
Verknüpfungen stellen die Verbindung zwischen den Knotenpunkten der binären
Baumstruktur dar und entsprechen genau den linken und rechten Referenzvariablen des
binären Suchbaumes.
Sequenzdiagramme
Der untere Teil von Abbildung 4.1 zeigt das Sequenzdiagramm des visualisierten
Programms. Sowohl die statischen Konturen als auch die Objekt-Konturen werden als
Kontext am oberen Ende des Sequenzdiagramms angezeigt. Die Methodenaktivierungen
werden als Rechtecke auf den vertikalen Lebenslinien ihres entsprechenden Kontextes
angezeigt. Die main-Methode ist die ganz links dargestellte Methodenaktivierung. Die
Methoden welche mit „<init>” benannt sind, kennzeichnen die Erzeugung eines neuen
Kontextes durch den Aufruf des jeweiligen Konstruktors. Java benutzt dieses Symbol
intern, um auf den Konstruktor zu verweisen und den Initializeraufruf zu instanziieren,
deshalb wird diese Notation auch hier benutzt. Der Benutzer kann durch das
Sequenzdiagramm scrollen und Kontexte oder Methodenaktivierungen auszuwählen. JIVE
wird daraufhin zu dem entsprechenden Konturendiagramm springen, welches diesen
Zustand repräsentiert.
Detaillierte Ansichten
Eine detailierte Ansicht zeigt den
kompletten Zustand eines Objekts,
und beinhaltet alle Elemente und
Methoden, von denen geerbt wurde.
Die Element-Tabellen zeigen die
definierten Variablen innerhalb des
Konturenkontextes. Die Tabellen
können so konfiguriert werden, dass
sie auch Methodendefinitionen
anzeigen. Es ist nicht generell nötig,
die Element-Tabellen für jede Kontur
Abbildung 4.2: Detaillierte Ansicht aus einer
anzuzeigen. Das Bildschirmfoto in
älteren Version von JIVE (0.21)
Abbildung 4.2 zeigt, wie strukturelle
Verknüpfungen zwischen Konturen
dargestellt werden. Die Verknüpfung startet bei der Zelle der entsprechenden Variable und
wird hin zu der referenzierten Kontur gezeichnet. Dies erlaubt strukturelle Verknüpfungen
zu dem richtigen implementierten statischen Variablenbereich bei Vererbung. MethodenKonturen repräsentieren Methoden-Aufrufe. Methoden-Konturen haben Element-Tabellen,
welche die lokalen Variablen einschliesslich der Parameter der Methode beinhalten. Die
Element-Tabellen von Methoden-Konturen oder Instanz- und statischen Konturen können
auf Wunsch versteckt oder angezeigt werden. Methoden-Konturen sind in ihrem statischen
Kontext eingebettet. JIVE zeigt den Quellcode für die aktuelle Methode an, und die
Samuel Strupp (349495)!
12
Visualisierung von Java-Programmen!
27.08.2005
momentan aktive Quellcodezeile wird sichtbar markiert. Es werden Markierungsfarben für
jeden Thread benutzt, um den momentanen Ausführungszustand klar ablesen zu können.
Aufruf-Pfad-Ansichten und minimierte Ansichten
Wenn Konturen minimiert sind, dann werden sie als
einfache Punkte dargestellt, wie in Abblidung 4.3 gezeigt.
In einer Aufruf-Pfad-Ansicht werden Konturen mit
Methodenaufrufen in der Kompakt-Ansicht, und die ohne
Methodenaufrufe in der minimierten Ansicht angezeigt.
Eine Aufruf-Pfad-Ansicht ist geeignet, um sich auf einen
bestimmten Methodenaufruf oder eine ganze Reihe von
Methodenaufrufen konzentrieren zu können. Die
allumfassende Struktur ist immer sichtbar, aber visuell
komplexe Details werden ausgeblendet. Wenn manche
Details uninteressant sind für den Benutzer, dann kann er
oder sie die komplette Kontur aus der Ansicht ausblenden.
Abbildung 4.3:
Es gibt Funktionen, welche alle Konturen expandieren,
Minimierte Ansicht
alle Konturen minimieren oder die Aufruf-Pfad-Ansicht
anzeigen. Zusätzlich kann der Benutzer die einzelnen
Konturen auswählen und wählen, ob er sie expandieren, minimieren oder die ElementTabelle ein- oder ausblenden möchte. Abbildung 4.3 zeigt ein Kontur-Diagramm, das
komplett minimiert wurde. Die komplett minimierte Ansicht ist sinnvoll, wenn man nur die
Gesamtstruktur betrachten will, ohne irgendwelche internen Details.
4.3.2 Kontursemantiken für Java
Java hat ein paar spezielle Eigenheiten, die nicht bei allen objektorientierten Sprachen zu
finden sind. JIVE muss allerdings auch diese speziellen Eigenschaften korrekt behandeln,
um sie korrekt darstellen zu können:
Statische Kontexte
In Java gibt es die Notation von statischen Elementen, welche bei dem objektorientierten
Standard-Kontur-Modell nicht vorgesehen ist. Variablen, Methoden und innere Klassen
können als statisch deklariert werden, und diese statischen Elemente werden mit einer
Klasse und nicht mit der Instanz einer Klasse assoziiert. Wenn nur eine statische Kontur
zu einer Klasse existiert, so wird kein Instanzenzähler benötigt. Der Aufruf einer statischen
Methode wird repräsentiert durch das Einsetzen einer Methoden-Kontur in die zugehörige
statische Kontur.
Samuel Strupp (349495)!
13
Visualisierung von Java-Programmen!
27.08.2005
Innere Klassen
Eine innere Klasse ist eine Klasse, die im Kontext
einer anderen Klasse definiert ist. Genauso werden
anonyme innere Klassen verarbeitet und es wird das
interne Nummerierungssystem von Java benutzt, um
anonyme Klassen zu identifizieren. Nicht statische
innere Klassen sind immer in genau einer
umschliessenden Instanz enthalten und so wird in
diesem Fall die Instanz-Kontur der inneren Klasse in
die Instanz-Kontur der umschliessenden Instanz
eingebettet. Nicht statische innere Klassen dürfen
keine statischen Elemente definieren. Statische
innere Klassen werden assoziiert mit dem statischen
Klassen-Kontext und so wird die Instanz-Kontur
einer statischen inneren Klasse in das Innere der
statischen Kontur der umschliessenden Klasse
eingebettet. Statische innere Klassen haben Abbildung 4.4: Kontur-Diagramm
statische Elemente, und so hat jede statische innere mit nicht statischer innerer Klasse
Klasse eine statische Kontur. Die statischen Konturen
von statischen inneren Klassen brauchen keine spezielle Behandlung und werden wie
jede andere statische Kontur behandelt. In Abbildung 4.4 sieht man ein Kontur-Diagramm
bei dem die Klasse „BST2” eine nicht statische innere Klasse „Node” definiert. Diese
innere Klasse instanziiert wiederum rekursiv eine weitere Instanz von „BST2”.
Überschreiben und Überdecken
Die Element-Tabelle jeder Instanz-Kontur besitzt in dem traditionellen Kontur-Modell für
objekt-orientierte Sprachen zwei interne Verknüpfungen. Eine this (oder self)Verknüpfung, welche zu dem innersten Objekt eines Stapels von Konturen führt und einen
super-Pointer, welcher auf die Kontur der Superklasse einer Kontur verweist, wenn eine
existiert. Der Sinn von this ist das Überschreiben von Methoden und das Überdecken
von Variablen zu zeigen. Eine this.print()-Anweisung wird immer die print()Methode, welche in der Klassenhierachie am tiefsten verankert ist, aufrufen. Es ist nicht
möglich, die Methode oder Variable zu erhalten, die von this referenziert wird. Deshalb
hat JIVE eine this-Referenz in der Element-Tabelle, die immer auf die innerste InstanzKontur zeigt, in einer Kollektion von eingebetteten Konturen. Die detaillierte Erklärung von
Überschreiben und Überdecken wird so einem Dritten überlassen.
Samuel Strupp (349495)!
14
Visualisierung von Java-Programmen!
27.08.2005
Threads
Threads sind ein elementarer Bestandteil von
Java. Mehrere gleichzeitige Threads implizieren
viele simultane Pfade von Methodenaufrufen. Das
ist ganz einfach im Konturenmodell repräsentiert
mit visuellen Stichwörtern bei Methoden und ihren
Return-Verknüpfungen. Jeder Threadpfad, der
gerade ausgeführt wird, wird in einer anderen
Farbe gezeichnet. Selbst wenn die selbe
Methodendefinition von verschiedenen Threads
aufgerufen wird, hat jeder Thread seinen eigene
Methodenkontur, da jeder Thread seinen eigenen
Stack besitzt. Um die verschiedenen Threads zu
markieren, werden die selben Farben benutzt,
sowohl im Kontur-Diagramm als auch im
Sequenz-Diagramm als auch im Quellcode. Ein
von JIVE erzeugtes Sequenzdiagramm ist in
Abbildung 4.5 dargestellt. Das Programm startet
Abbildung 4.5: Mehrere Threads
einfach zwei Threads und lässt sie bis zur
in einem Sequenzdiagramm
Endbedingung laufen.
4.4 Die Architektur von JIVE
Nachdem Gestwicki und Jayaraman in vorhergehenden Projekten versucht haben,
Programmvisualisierungen durch Programm-Transformation darzustellen, haben sie diese
Methode zugunsten einer Zwei-Prozess-Architektur aufgegeben. Der Grund hierfür liegt
darin, dass bei jeder Weiterentwicklung von Java die selbstgeschriebenen Compiler und
Interpreter auch wieder umgeschrieben werden müssen. Bei der in JIVE eingesetzten
Zwei-Prozess-Architektur läuft die Visualisierungsumgebung selbst als ein Prozess. Der
Benutzer gibt JIVE das Programm an, welches er visualisieren möchte, und JIVE startet
das Programm in einem zweiten Prozess, dem so genannten „Client Prozess”. Die
Kommunikation zwischen den beiden Prozessen wird durch die Java Plattform Debugger
Architektur möglich gemacht (JPDA). Um den Quellcode anzeigen und markieren zu
können, muss der Quellcode des Programms geladen werden, aber JIVE kann auch
Visualisierungen von kompilierten Klassen erzeugen, solange diese noch DebuggerInformationen bereit halten. JIVE unterstützt Multithread-Programme, welche für den
Einprozessor-Betrieb ausgelegt sind, aber das System unterstützt momentan keine
verteilten oder Multiprozessor-Programme. Wenn JIVE erst einmal den Client-Prozess
gestartet hat, registriert es Event-Listeners via JPDA und wartet auf Benachrichtigungen.
Wenn sich der Clientzustand ändert, wird der Client-Prozess angehalten und die
Benachrichtigung des Ereignisses wird an JIVE gesendet. Wenn das Datenmodell und die
verschiedenen Ansichten aktualisiert wurden, kehrt JIVE wieder zum Client-Programm
zurück und wartet auf neue Ereignisse. Die Menge von Schritten, die der Client ausführt,
bevor er wieder angehalten wird, ist abhängig von den Benutzereinstellungen. JIVE
erlaubt verschiedene Schrittgrößen, welche einzelne Quellcodezeilen, Methodenaufrufe
oder traditionelle Breakpoints im Quellcode beinhalten. Es ist auch möglich, die
Eventsperre zu deaktivieren, in diesem Fall werden die Ereignisse ununterbrochen an
JIVE gesendet, welches diese dann sequenziell abarbeitet.
Samuel Strupp (349495)!
15
Visualisierung von Java-Programmen!
Client
Prozess
JPDA
JIVE
27.08.2005
Programm
Zustands
Model
Objekt
Diagramm
Ausführungs
Protokoll
Interaktives
Interface
Anfrage
Interface
Ausführungs
Datenbank
Programm
Geschichts
Model
Sequenz
Diagramm
JIVE GUI
Abbildung 4.6: JIVE Architektur. Die Boxen repräsentieren JIVE-Module und die Pfeile
repräsentieren Daten- und Kontrollfluss
Die Ablaufstruktur von JIVE ist wie folgt: Wenn das Client-Programm läuft, wird es auf
Veränderungen überwacht. Die Änderungen werden in das Ausführungs-Protokoll
aufgenommen, wie in Abbildung 4.6 dargestellt. Das Protokoll ist gekoppelt mit einer
Datenbank, in der die Ausführungsgeschichte gespeichert wird. Ausführungs-Ereignisse,
die vom Client empfangen werden, werden als einfachere Menge von Ereignissen von
JIVE interpretiert. JIVE benutzt die folgenden Ereignisse: statische Kontext-Erzeugung,
Objekt-Erzeugung, Methodenaufruf, Methodenreturn, ausgelöste und abgefangene
Exceptions, Änderung in der Quellcodezeile, Änderung eines Variablenwertes. Jedes
dieser Ereignisse ist gekapselt als ein Objekt, und jedes dieser Objekte enthält genug
Informationen über das Ereignis, um entscheiden zu können, ob es sich selbst an das
Ausführungs-Protokoll übergibt oder nicht. Im Wesentlichen enthält jedes Ereignis
Informationen über die Änderungen, welches es an dem Ausführungszustand vornehmen
wird.
Werden in JIVE ältere Ausführungszustände betrachtet, hat dies keinen Effekt für das
Client-Programm, sondern nur für die aktuellen Visualisierungen. Das Client-Programm
wird angehalten, während der Benutzer vergangene Zustände begutachtet, und es wird
erst wieder fortgesetzt, wenn es nötig ist. Da das Modell die Möglichkeit von sich
ändernden Programm-eingaben verhindert, meidet es auch das Problem der
beibehaltenen Synchronisation von externen Ressourcen, wie Datenströmen oder Ein-/
Ausgabe Geräten. Wenn zum Beispiel ein Programm mit einer grafischen Benutzeroberfläche in JIVE ausgeführt wird und der Benutzer in der Ausführungsgeschichte zurück
geht, wird das Interface nicht reagieren, da der Client-Prozess angehalten wurde. Da JIVE
auf Einprozessor-Systeme beschränkt wurde, gibt es auch immer nur eine Instruktion, die
zu einer bestimmten Zeit aufgeführt wird. Deshalb können auch Multithread-Programme
ohne Probleme visualisiert werden. JIVE weiß, welches Ereignis von welchem Thread
kommt. Der aktive Thread ist im Ausführungsprotokoll verzeichnet und das wird in der
Visualisierung reflektiert (siehe Abbildung 4.5).
Es ist möglich, Kontur-Diagramme in Multigraphen zu konvertieren. Verschiedene
Gewichte können zu den verschiedenen Typen von Verknüpfungen zugeordnet werden.
Durch Experimente fanden Gestwicki und Jayaraman heraus, dass strukturelle
Verknüpfungen permanenter als Methoden-Return-Verknüpfungen sind, und deshalb
werden strukturelle Verknüpfungen höher gewichtet bei der Umwandlung in einen
Multigraph. Der resultierende Graph wird dann unterteilt von einer modifizierten CoffmanSamuel Strupp (349495)!
16
Visualisierung von Java-Programmen!
27.08.2005
Graham Unterteilung [7] für Multigraphen und das Kreuzen wird minimiert [6]. Das
Ergebnis ist eine unterteilte Graphenzeichnung. Eine „Inverse Transformation” wird
angewandt, um aus dem Multigraph wieder das Kontur-Diagramm zu erhalten. Dies
funktioniert sehr gut für einfache Strukturen, wie Bäume oder grafische
Benutzeroberflächen-Kompositionen. JIVE unterstützt viele Ansichten mit vielen
verschiedenen Detailstufen. Es gibt verschiedene Modelle, um Visualisierungen zu filtern.
Zum Beispiel kann man einen Filter erzeugen, der alle Klassen von der Visualisierung
ausnimmt, welche mit „java” beginnen.
Die Geschichtsdatenbank speichert alle bisher aufgetretenen Ereignisse im Programm. So
repräsentiert sie den kompletten Ablauf des Programms seit dem Programmstart. Das
bietet den Vorteil, dass man im Ablauf des Programms interaktiv vor und zurück gehen
kann. Die Speicherstruktur der Geschichtsdatenbank kann aufgefasst werden als eine
objekt-orientierte Datenbank von Laufzeitzustandsinformationen. In dieser
Laufzeitzustandsdatenbank werden Anfragen auf die Geschichte der Laufzeitausführung
durchgeführt oder auf Teile davon und die Ergebnisse sind Werte, Mengen von Zuständen
oder Teile der Programmgeschichte. So können Anfrage und Ergebnis visualisiert werden.
Ein Grund für das Benutzen einer Laufzeitdatenbanken ist das Verfolgen von
Variablenwerten. Eine Variable wird in JIVE ausgewählt und deren Wert wird auf
Änderungen überwacht. Der Benutzer spezifiziert eine Bedingung für die Variable wie:
Wert wurde geändert oder Wert liegt innerhalb einer bestimmten Wertemenge. Das
Ergebnis der Variablenverfolgung wird in der JIVE-Benutzeroberfläche angezeigt. Die
Geschichtsdatenbank erlaubt es auch, die Ausführungsdaten in eine Datei zu schreiben.
Ein Programm-Geschichts-Datei kann wieder geladen und visualisiert werden. Diese
Serialisierung der Ausführungsgeschichte macht es auch möglich, verschiedene Abläufe
des selben Programms zu vergleichen. Wenn viele Ausführungsgeschichten existieren,
können kleine Veränderungen im Ablauf unterschiedlicher Programmversionen visualisiert
werden.
4.5 Kurzer Ausblick in die Zukunft
Probleme gibt es bei JIVE vor allem noch bei der guten Darstellung von strukturierten
Diagrammen. Wie kann man z.B. ein dynamisch wachsendes Sequenzdiagramm
möglichst effektiv strukturieren? Auch die Struktur der Objektdiagramme kann sicher noch
verbessert werden. Zudem wäre es wünschenswert, wenn man nicht nur Einzelschritte
vorwärts und rückwärts gehen könnte, sondern auch von einem Zustand in einen weiter
entfernten Zustand wechseln könnte, ohne dass alle dazwischen liegenden Zustände
ausgeführt werden müssen. Das ist mit diesem Modell allerdings nicht möglich! Eine
weitere Idee ist das Analysieren von Quellcodedateien, um Abhängigkeiten zwischen
Methoden und Daten zu ermitteln und so für verschiedene Arten von Programmen die
besten Ergebnisse zu liefern. Auch die Anfragen an die Geschichtsdatenbank können
noch verbessert und erweitert werden. Die Daten aus der Geschichtsdatenbank könnten
auch von anderen Programmen genutzt werden, um Programmanalysen durchzuführen.
Zum Beispiel, wenn es um die Sicherheit geht. Wenn man ein Programm mehrmals laufen
lässt, ist es vielleicht möglich, eine mathematische Beschreibung zu extrahieren, was ein
„normaler” Ablauf ist. Verhält sich ein Programm dann extrem anders, kann es so als
potenzielles Risiko eingestuft werden. Das Ergebnis eines solchen Vergleichs kann
wiederum mit JIVE dargestellt werden.
Samuel Strupp (349495)!
17
Visualisierung von Java-Programmen!
27.08.2005
5. JOVE
5.1 Über JOVE
JOVE wird von Steven P. Reiss und Emmanuel Manos Renieris am „Department of
Computer Science” an der Brown Universität entwickelt [2]. JOVE ist ein Java
Visualisierungswerkzeug, welches Darstellungen eines Java Programms auf StatementEbene bietet, während dieses ausgeführt wird. JOVE profitierte bei der Entwicklung von
dem vorhergehenden Projekt Namens JIVE, das ein anderes Visualisierungswerkzeug für
Java Programme ist (dieses JIVE ist nicht das selbe JIVE, das von Gestwicki und
Jayaraman entwickelt und in Kapitel 4 beschrieben wird).
5.2 Anforderungen an JOVE
Das ältere System JIVE erfüllte bereits ein paar wesentliche Anforderungen:
• Einen minimalen Overhead, so dass das System von jedem Programm benutzt werden
konnte, und das zu jeder Zeit.
• Das Maximale an gesammelten Daten darzustellen und zwar so, dass komplexe,
miteinander agierende Muster erkennbar sind und somit auch das Verhalten besser zu
verstehen ist.
• Eine Ausführungsgeschichte bereitzustellen, damit der Benutzer sich den Ablauf des
Programms noch einmal ansehen kann oder interessante Ausführungszustände
inspizieren kann.
• Die Darstellungen so anzeigen, dass verschiedene Arten von Verhalten des Programms,
welche von besonderer Bedeutung sein könnten, besonders hervorgehoben werden,
beispielsweise durch Farbe und Größe.
• Dem Benutzer die Möglichkeit geben, die Darstellung an seine speziellen Probleme
anzupassen.
Allerdings gibt es auch ein paar Punkte, die JIVE nicht erfüllen konnte, welche aber von
JOVE erfüllt werden sollen:
• Informationen darüber, wo im Quellcode sich die Ausführung gerade befindet, um
feststellen zu können, in welchen Bereichen das Programm viel Zeit verbringt.
• Informationen darüber, welche Instruktionsausführungen mit welchem Thread in
Verbindung stehen, so dass nachvollzogen werden kann, was ein Thread gerade macht
und nicht nur, in welchem Zustand er sich befindet.
Alle diese Punkte sind Anforderungen, die JOVE erfüllen soll. Das Konzept für JOVE
konzentriert sich also vor allem auf die Datensammlung über den Programmablauf, welche
zudem threadspeziefisch aufgeschlüsselt wird.
5.3 Lösungen in JOVE
JOVE unterteilt die subjektive Programmausführung in Intervalle von etwa 10
Millisekunden. In jedem Intervall registriert JOVE, was das Programm in jedem seiner
Samuel Strupp (349495)!
18
Visualisierung von Java-Programmen!
27.08.2005
Threads macht. Um dies realisieren zu können, benutzt JOVE so genannte Basisblöcke,
um spätere Rechen- und Performance-Analysen durchführen zu können. Ein Basisblock
ist ein Segment von reinem Zeilencode ohne interne Verzweigungen. Das bedeutet, wenn
solch ein Block gestartet wird, dann werden auch alle Instruktionen des Blocks ausgeführt.
Man kann jetzt zählen, wie oft einzelne Instruktionen ausgeführt werden, indem man
einfach zählt, wie oft der zugehörige Block durchlaufen wurde. Aus diesen Informationen
und aus den Informationen vom Debugger, welche Ausdrücken, welche Instruktionen
welchen Zeilen im Code entsprechen, können dann die Basisblock-Zählungen benutzen
werden, um die Häufigkeit der Ausführung bestimmter Zeilen und deren Anzahl der
Maschinen-Instruktionen pro Zeile zu ermitteln. Die Messwerte, die JOVE registriert, sind
Tupel der Form <I,T,B,c>, wobei I das Intervall identifiziert, T den Thread, B den
Basisblock und c die Anzahl der Ausführungen des Basisblocks B durch den Thread T im
Intervall I. JOVE erweitert die Basisblock Zählungen um Zählungen von Allokationen und
ausgeführten Instruktionen durch eine statische Analyse der Basisblöcke. Es ordnet diese
Statistiken auf verschiedene Weisen, zum Beispiel nach Datei oder nach Thread und
bildet die Ergebnisse auf visuelle Elemente in einer informationsverdichteten Darstellung
ab.
Abbildung 5.1: Beispiel einer JOVE-Visualisierung
Das Visualisierungsfenster von JOVE ist in mehrere vertikale Regionen unterteilt. Jede
Region entspricht dabei einer Datei des zu visualisierenden Systems. Jede
Dateivisualisierung ist wieder unterteilt in einen oberen Teil, in welchem die
Threadinformationen dargestellt werden, und in einen unteren Teil für die
Blockinformationen (siehe Abbildung 5.1). In der unteren Region ist ein horizontales
Rechteck für jeden Basisblock. Diese Rechtecke sind geordnet nach der Nummer der
entsprechenden Quellcodezeilen. Diese zwei Regionen der Darstellung müssen
dynamisch geändert werden können entsprechend den gesammelten Daten des
kompletten letzten Intervalls. Das Ergebnis ist dementsprechend eine Animation des
laufenden Programms.
Der größte Teil der Visualisierung bezieht sich immer auf das letzte Intervall. Die Breite der
entsprechenden Dateispalte reflektiert allerdings den kompletten Ablauf für diese Datei bis
zum momentanen Intervall und entspricht dem prozentualen Anteil der Anzahl von
Instruktionen, welche in dieser Datei über den gesamten Ablauf ausgeführt wurden. Der
obere Teil jeder Dateidarstellung enthält ein Kreisdiagramm. Das Innere des
Kreisdiagramms stellt die gesamte Ablaufzeit des momentanen Intervalls innerhalb der
Samuel Strupp (349495)!
19
Visualisierung von Java-Programmen!
27.08.2005
Datei dar. Das Kreisdiagramm ist in Sektoren aufgeteilt. Jeder Sektor entspricht dabei der
prozentual verbrachten Zeit in einem bestimmten Thread. Die Standardhintergrundfarbe
für jede vertikale Region kodiert drei verschiedene Statistiken. Der Farbton stellt die
Anzahl der Instruktionen, die im letzten Intervall ausgeführt wurden, über ein grün zu gelb
Farbmodell da. Die Sättigung gibt die Anzahl der Ausführenden Threads im aktuellen
Intervall wieder. Und die Helligkeit die Anzahl der Allokationen, die von Blöcken in dieser
Datei im aktuellen Intervall gemacht wurden. Wenn kein Code in der Datei während dem
Intervall ausgeführt wurde, wird der Hintergrund grau dargestellt. Die Basisblöcke einer
Datei werden jeweils im unteren Teil der Dateiregion durch ein horizontales Rechteck
dargestellt. Die Höhe des Rechtecks entspricht der Anzahl von Quellcodezeilen. Die Breite
des Rechtecks korrespondiert zu der Anzahl von Instruktionen, die in dem Basisblock im
letzten Intervall ausgeführt wurden. Die Linie ist aufgeteilt in viele farbige Regionen, bei
der jede einem Thread entspricht. Die Farbgebung entspricht dabei der des
Kreisdiagramms.
Abbildung 5.2: Dialogboxen um JOVE zu konfigurieren
Jeder Benutzer kann JOVE so einstellen, dass er eine geeignete Ansicht seiner
Applikation bekommt. Innerhalb von JOVE kann der Benutzer Dialogboxen benutzen,
welche in Abbildung 5.2 gezeigt sind, um die verschiedenen Kommandozeilenargumente
einzustellen, um die Intervallgrößen zu ändern, um Klassen zu definieren, welche
dynamisch geladen werden und nicht statisch auffindbar sind, aber überwacht werden
sollen, und um festzulegen, welche Pakete und Klassen überwacht werden sollen und
welche ignoriert werden sollen. Der Benutzer kann auch kontrollieren, welche Statistiken
angezeigt werden sollen und auf welche Weise (Abbildung 5.2, rechte Dialogbox). Er kann
auch zwischen totalen oder sofortigen Werten wählen für alle statistischen Eigenschaften.
Desweiteren kann der Benutzer zwischen linearer, Quadratwurzel- oder logarithmischer
Skalierung wählen, um die verschiedenen Aufteilungen dieser Werte mit diesen
Eigenschaften zu betrachten. Zudem sind weiter Darstellungsdetails, wie z.B. Farbmodelle
veränderbar.
5.4 Die Architektur von JOVE
Die Kontrollkomponente von JOVE stellt dem Benutzer ein einfaches Interface zu
Verfügung. Dort kann der Benutzer definieren, welches Programm überwacht werden soll,
Argumente können eingestellt oder geändert werden, die sich auf den Java-Interpreter
Samuel Strupp (349495)!
20
Visualisierung von Java-Programmen!
27.08.2005
oder den Benutzercode beziehen. Zudem ist es möglich, einzustellen, welche Klassen
oder Pakete überwacht und welche ignoriert werden sollen.
Die Aufbaukomponente ist ein unabhängiger Prozess, welche alle Klassen, die
überwacht werden sollen, identifiziert und welche diesen Klassendateien den benötigten
Code für die Überwachung hinzufügt. Dieser „Patcher” benutzt das IBM JikesBT byte code
Toolkit [5]. Diese Komponente produziert zwei Ausgaben. Die erste ist eine jar-Datei,
welche die modifizierten Klassen beinhaltet. Dieses wird benutzt, um die originalen
Klassendateien zu ersetzen, wenn das Programm abläuft. Die zweite Ausgabe ist eine
Beschreibungsdatei, welche Informationen über jeden Basisblock auflistet: zu welcher
Methode und Klasse der Block gehört, die entsprechende Quellcodezeile, die Anzahl der
Instruktionen und Allokationen in diesem Block und die Typen der Objekte, die von den
Allokationen erzeugt werden. Die zweite Datei wird vom Visualisierer benutzt, die
Zähldaten der Basisblöcke in aussagekräftigere Informationen für den Benutzer
umzuwandeln.
Die Information-Sammlungs-Komponente ist eine kleine Bibliothek, die mit dem
Benutzerprogramm geladen wird. Die Bibliothek wird zu Beginn von dem veränderten
Code aufgerufen. Sie ist zuständig für die Zählungen und das dynamische zur Verfügung
stellen der passenden Daten für den Visualisierer. Der Schlüssel zu einem erfolgreichen
dynamischen Echt-Zeit-Visualisierungssystem ist Sammeln der angemessenen
Verfolgungsdaten mit einem minimalen Overhead. Für JOVE bedeutet das zu zählen, wie
oft jeder Basisblock in jedem Thread in einem Intervall ausgeführt wurde. Es ist kein
Nachteil, Informationen auf Basisblockebene statt auf Methodenebene zu sammeln. Auf
Methodenebene muss nicht nur jeder Methodeneintritt und -austritt verändert werden,
sondern es müssen auch Allokationen oder unnormale Austritte durch Exceptions
beachten werden. Diese Erfordernisse müssen auf der Basisblockebeneverfolgung nicht
berücksichtigt werden, da Informationen über Allokationen in den Basisblock
Informationen enthalten sind, da davon ausgegangen werden kann, dass in fast allen
Fällen feststeht, welche Objekte alloziert werden, wenn ein Block ausgeführt wird.
Zweitens, falls ein Block einen Exception-Handler repräsentiert, kann diese Exception über
die Ausgabesequenz festgestellt werden. Ein Problem ist, wie man an Basisblockinformationen kommt, in denen die Zählungen mit den aktuellen Thread assoziiert werden.
Die Lösung des Problems ist das Hinzufügen eines zusätzlichen Parameters zu jeder
Routine, welcher den aktuellen Kontext beinhaltet, welcher wiederum den aktuellen
Thread und die Zählinformationen für diesen Thread beinhaltet. Reiss und Renieris
realisierten dies durch das Erzeugen einer Schatten-Routine für jede Routine, die
überwacht werden soll. Der Name der Original-Routine wird geändert, der KontextParameter hinzugefügt genauso wie der Code, welcher die entsprechende Methode für
den Basisblockeintritt aufruft. Dann wird eine neue Routine mit dem Original-Namen und
Parametern erzeugt. Die neue Routine errechnet den Kontext (indem sie den aktuellen
Thread findet und dann den Kontext bei diesem nachsieht) und ruft danach die
modifizierte Original-Routine auf. Alle Aufrufe von Routinen des veränderten Codes
werden dann noch so verändert, dass die korrespondierenden umbenannten Routinen
aufgerufen werden. Diese Lösung bedeutet, dass beinahe alle Aufrufe, die im
modifizierten Code gemacht werden, die modifizierten Original-Routinen benutzen und
nicht einen neuen Kontext berechnen müssen. Außerdem können korrekte Aufrufe von
unmodifiziertem Code und Routinen, welche Interfaces oder abstrakte Methoden
implementieren behandelt werden. Um Blöcke in einem Thread effizient zählen zu können,
braucht man den Kontext von jedem Thread vorallokierte Zählpuffer für Zählungen jedes
enthalten Basisblocks in der überwachten Quelle. Der Code beim Basisblockeintritt
Samuel Strupp (349495)!
21
Visualisierung von Java-Programmen!
27.08.2005
inkrementiert einfach den entsprechenden Zähler für den aktuellen Kontext. Ein
Kontexttriple puffert diese Zählungen. Der erste Puffer enthält die aktuellen Zählungen. Ein
zweiter Puffer wird benutzt, um die Daten zu halten, welche momentan verarbeitet werden,
um an das Visualisierungs-Front-End gesendet zu werden. Ein dritter Puffer, welcher das
vorhergehende Intervall repräsentiert, ist verfügbar, um Vergleiche mit dem zweiten
durchführen zu können. Die aktuelle Sammlung und das Melden der Daten zu dem
Visualisierungs-Front-End wird durch einen seperaten Thread erledigt, welcher einen
Timer ablaufen lässt, der wiederum die Intervalle errechnet. Dieser Thread behandelt auch
das Puffer-Swapping, produziert eine XML-Nachricht, welche die nicht Null Zählungen
zusammen fasst und sendet diese Nachricht über ein Socket zum Visualisierer.
Die Visualisierungskomponente stellt zwei Ansichten zur Verfügung. Eine ist eine
Mitschrift der Ein- und Ausgaben des Programms. Die zweite ist die Hauptansicht der
gesammelten Informationen wie in 5.3 beschrieben. Diese Komponente ist zuständig für
das Speichern und Zugreifen auf die dynamischen Informationen, für das Erzeugen von
angemessenen Ansichten, die auf den Benutzereinstellungen basieren, für das
dynamische Aktualisieren dieser Ansicht, während das Programm abläuft, und für das
Bereitstellen eines zeitbasierten Zugriffs auf die Daten. Informationssammlungen ergeben
Basisblock Zählungen für jedes Intervall für jeden Thread oder Kontext. Für die
Darstellung werden diese Informationen nach dem Kontext und global für jede Quelldatei
gesammelt. Wie werden die Informationen jetzt effizient dargestellt? Wie schon erwähnt
gibt es 3 Basistypen an Informationen, welche dargestellt werden können:
1. Informationen über die individuellen Basisblöcke und daraus resultierende Quellzeilen:
!
- Anzahl der Ausführungen!!
!
!
!
für jeden individuellen Thread
!
- Anzahl der gemachten Allokationen !
!
für jeden individuellen Thread
!
- Anzahl der ausgeführten ByteCodes!
!
für jeden individuellen Thread
!
- Anzahl der Ausführungen!!
!
!
!
für alle Threads zusammen
!
- Anzahl der gemachten Allokationen !
!
für alle Threads zusammen
!
- Anzahl der ausgeführten ByteCodes!
!
für alle Threads zusammen
2. Informationen über Dateien:
!
- totale Zählungen der verschiedenen Statistiken von allen Blöcken
!
!
!
!
!
!
!
!
!
!
für jeden individuellen Thread
!
- totale Zählungen der verschiedenen Statistiken von allen Blöcken
!
!
!
!
!
!
!
!
!
!
für alle Threads zusammen
3. verschiedene Statistiken geordnet nach Threads
Alle drei Informationstypen sollen in der selben Ansicht dargestellt werden. Dabei muss
sichergestellt sein, dass so viele Daten wie möglich dargestellt werden, und dass
interessante Werte, besondere mögliche Performanceprobleme, Threadkonflikte und
interessante Veränderungen im Verhalten hervorstechen. Wie in Kapitel 5.3 beschrieben
ist die Ansicht in vertikalen Dateiregionen organisiert, bei der jede ein Kreisdiagramm für
Kontexte beinhaltet, und eine Ansicht der Basisblöcke. Globale Dateiinformationen werden
durch die Datei-Regionsgröße, Hintergrundfarbe, und den Bereich zwischen dunklem und
hellen Hintergrund reflektiert. Die Rolle der Kontexte in der Datei innerhalb eines Intervalls
wird durch das Kreisdiagramm wiedergespiegelt. Rechtecke in der Basisblockregion
reflektieren den Kontext, Allokationen und die Anzahl der Instruktionen, welche während
dem Intervall ausgeführt wurden. Das Entscheidende bei der JOVE-Darstellung ist die
Möglichkeit, viele Dimensionen der Daten auf einem sinnvollen Weg darzustellen. Die
Samuel Strupp (349495)!
22
Visualisierung von Java-Programmen!
27.08.2005
normale Dateiansicht zeigt fünf verschiedene Statistiken und benutzt dabei die Breite, den
Farbton, die Sättigung, die Helligkeit und die Position von den Unterteilungslinien. Das
Kreisdiagramm zeigt die verschiedenen Kontexte durch Farben und kann durch die
Kreisabschnittsgröße verschiedene Statistiken über den Kontext reflektieren (z.B.
Allokationen und Instruktionen). Die Basisblöcke können bis zu fünf Statistiken enthalten
mit ihrer Breite, Höhe, Farbton, Sättigung und Helligkeit.
Da die Ansicht eine Menge an Informationen zu
Verfügung stellt, muss der Programmierer sie mit
dem Ursprungsprogramm in Verbindung setzen
können. Anstatt den Daten Bezeichnungen zu
geben (wo der Text oft zu klein zum Lesen wäre),
werden Tooltips benutzt welche dem Benutzer
Abbildung 5.3: Tooltip in JOVE
detaillierte Informationen zur Verfügung zu stellen.
Abblidung 5.3 zeigt einen solchen Tooltip, welcher
angezeigt wird, wenn man die Maus über einer Fläche der Visualisierung platziert.
Datenstruktur
Bei einem lange laufenden Programm kann eine große Anzahl von Intervallen existieren,
wobei jedes signifikante Daten enthält. Zum Beispiel in einem relativ einfachen Spiel
existieren etwa 3000 Basisblöcke, die verfolgt werden müssen für jedes Intervall und für
jeden der vierzehn aktiven Threads. Des weiteren wird die Möglichkeit des Zugriffs auf die
zusammenfassenden Zähler für Dateien und Threads benötigt. Dies ist nicht einfach, da
unterschiedliche Statistiken separat gesammelt werden müssen (Allokationen,
Instruktionen und Blockzählungen), da diese nicht von den rohen Zählimpulsen direkt
abgeleitet werden können, wie es für die BasisIntervalle:
blöcke gemacht werden kann. Um diese Daten zu
speichern, haben Reiss und Renieris einen Vektor
Lokal
Global
von Intervallen kreiert. Jedes Intervall wird
Block 1
Block 1
repräsentiert durch zwei Hash-Tabellen, eine für
Block 2
Block 2
Block n
Block n
die lokalen Daten des Intervalls und eine für die
Datei 1
Datei 1
Datei 2
Datei 2
totalen Daten bis und einschliesslich diesem
Total
Total
Intervall. Jede Hash-Tabelle ist indiziert durch den
Block i
Block i
Block oder Datei, wo der assoziierte Wert ein
Thread 1
Thread 1
Thread 2
Thread 2
Statistiken
Statistiken
andere Hash-Tabelle ist. Für jedes individuelle
<#Blöcke>
<#Blöcke>
Total
Total
<#Instanzen>
<#Instanzen>
Objekt, bildet diese zweite Hash-Tabelle den
<#Allokationen>
<#Allokationen>
Kontext (Thread) auf einen Block von
Abbildung 5.4: Datenstruktur um die Zähler-Informationen zu speichern
Statistischen Werten, welche die verschiedenen
Zählungen repräsentieren. Ein spezieller Kontextwert wird benutzt, um den globalen
Kontext zu repräsentieren. Dies alles ist in Abbildung 5.4 dargestellt. Alle Zählungen des
Informationssammlers auf Blockebene werden zuerst in die lokalen Tabellen eingetragen.
Jede Zählung ungleich Null generiert einen Statistikeintrag für den entsprechenden Block
und Thread (auf beiden Ebenen der Hash-Tabelle). Die Totalzählung für alle Threads wird
als separate Statistik berechnet von den lokalen Totalen. Genauso wird jede Blockzählung
in die entsprechenden Einträge für die Datei eingetragen, welche in der ersten HashTabelle indiziert wurde. Zuletzt werden die Totalen von jedem Eintrag berechnet. Das
Ergebnis ist eine komplettes Set von Statistiken ungleich Null für jedes Intervall. Dieses
kann schnell indiziert werden, nach Block, Datei oder Thread. Für jeden Eintrag in den
vorhergehenden Totalen die keinen entsprechenden lokalen Eintrag haben, wird einfach
auf den vorhergehenden Block verwiesen. Andernfalls wird ein neuer Eintrag erzeugt
Samuel Strupp (349495)!
23
Visualisierung von Java-Programmen!
27.08.2005
welcher die Summe von jedem vorhergehenden totalen Eintrag und die neuen lokalen
Werte beinhaltet. Durch diese Methoden entsteht ein speichereffizienter
Lagermechanismus, welcher zügigen Zugriff auf alle verfügbaren Statistiken bietet und die
Tatsache in Betracht zieht, dass die meisten Zählungen Null ergeben.
5.5 Kurzer Ausblick in die Zukunft
Mit JOVE braucht ein Programm etwa drei bis viermal so viel Zeit wie normal. Eigentlich ist
diese Verlangsamung akzeptabel, aber es kann vielleicht noch optimiert werden. Ein
weiterer Punkt ist das Erheben von noch mehr Daten eines Programmdurchlaufs, was
dann aber natürlich eine weitere Verlangsamung mit sich bringt. Oder das Beobachten des
Speichers. In Java ist es relativ einfach, Allokationen zu registrieren, aber Deallokationen,
die letztlich vom Garbage Collector durchgeführt werden, sind viel schwieriger. Und noch
ein interessanter Punkt ist das Assoziieren des Programmverhaltens mit Ereignissen wie
Eingaben oder generierten Ereignissen. So könnte man bestimmen, welche Prozesse
ausgeführt werden bei einer bestimmten Eingabe.
6. Zusammenfassung und eigene Meinung
Die beiden vorgestellten Programme „JIVE” und „JOVE” sind also Javaprogrammvisualisierungswerkzeuge, welche ein paar der vorgestellten Ideen aus Abschnitt 3
umsetzen (Quellcode, Objektstrukturen, Instanzen, ...). Die Anforderungen, die an das
jeweilige Projekt gestellt wurden, sind im Wesentlichen erfüllt worden. JIVE eignet sich,
um in der Lehre die Struktur und Funktionsweise von objektorientierten Sprachen zu
vermitteln. Es ist auch durchaus als visueller Debugger einsetzbar. JOVE erreicht auch
sein Ziel, langsamen Quellcode zu identifizieren. Allerdings sind beide Werkzeuge nur für
kleine, nicht so komplexe Programme geeignet, da schnell die Skalierbarkeit der
Darstellung sowie der Datenerhebung und Datenverarbeitung erreicht ist und das jeweilige
Programm so nicht mehr benutzbar wird. Ein weiteres Manko von Seiten der Entwickler
ist, dass beide Programme im Moment nicht in der aktuellen Version im Netz verfügbar
sind.
Samuel Strupp (349495)!
24
Visualisierung von Java-Programmen!
27.08.2005
7. Literaturangaben
[1] ! Paul Gestwicki, Bharat Jayaraman
!
„Methodology and Architecture of JIVE”
!
ACM symposium on Software visualization (2005)
[2]!
!
!
Steven P. Reiss, Emmanuel Manos Renieris
„JOVE: Java as it Happens”
ACM symposium on Software visualization (2005)
[3]!
!
!
Katharina Mehner
„JaVis: A UML-Based Visualization and Debugging Environment for Concurrent Java
Programs” (2001)
[4]!
!
Wim De Pauw, Erik Jensen, Nick Mitchell, Gary Sevitsky, John Vlissides, Jeaha Yang
„Visualizing the Execution of Java Programs” (2001)
[5]!
!
Chris Laffra, Doug Lorch, Dave Streeter, FrankTip, John Field
„What is Jikes Bytecode Toolkit” http://www.alphaworks.ibm.com/tech/jikesbt (2000)
[6]!
!
P. Eades, G. Di Battista, R. Tamassia, and I. G. Tollis.
„Graph Drawing: Algorithms for !the Visualisation of Graphs” (1999)
[7]!
!
E. G. Coffman, Jr. und R. L. Graham
„Optimal scheduling for two-processor systems.” Acta Informatica (1972)
[8]!
!
!
Blaine Price, Ronald Baecker, Ian Small
„An Introduction to Software Visualization”
Software Visualization – Programming as a Multimedia Experience (1998)
[9]!
!
Azureus - Java BitTorrent Client
http://azureus.sourceforge.net
Hilfreiche Seiten waren außerdem:
http://www.software-kompetenz.de
http://www.wikipedia.de
Samuel Strupp (349495)!
25
Herunterladen