Eclipse Memory Analyzer MAJUG November 2008

Post on 18-Jul-2015

919 views 1 download

Transcript of Eclipse Memory Analyzer MAJUG November 2008

1

2

3

4

Ein Garbage Collector sorgt dafür dass nur die Objekte dir noch erreichbar sind im Speicher bleiben.Nicht erreichbare Objekte können dem Programm nicht mehr von Nutzen sein und können dahergelöscht werden.

Wann der GC Objekte löscht ist typischerweise nicht determiniert. Dies steht im Gegensatz zuReference Counting, dass z.B. in C++ gerne als einfache automatische Speicherverwaltung genutztwird.

5

Malloc muss normalerweise eine Liste freier Speicherbereiche verwalten ->Malloc typischerweiselangsamer als ein new in Java

6

Das eigentliche Problem sind die versteckten Kosten des GC.

Praktisch jede GC Implementierung erfordert eine „stop the world“ Phase, bei der alleApplikationsthreads angehalten werden müssen.

Der Benutzer hat dann den Eindruck einer nicht vorhersagbaren Antwortzeit.

7

„Normaler“ Garbage Collector log

http://www.tagtraum.com/gcviewer.html

Der Speicherverbrauchstrend zeigt keinen Anstieg. Daher liegt hier wohl kein Memory Leak vor

Je kleiner der Speicherverbrauch nach einem Full GC ist desto weniger Full GC‘s müssen bei sonstgleichen Bedinungen ausgeführt werden

8

9

Shallow size == flache Grösse des Objektes. Die Shallow Size ist in der Praxis ein nützliches Maß fürden Overhead eines Objektes.

„object header“ : Jedes Java Object (in der SUN/SAP JVM) hat einen Header, der Informationen überdas Object Layout, Type, GC Zustand, Synchronization Status, und identity hash code enthält. DerObject header ist 2 Worte (8Bytes unter 32 bit) groß.

10

Man beachte :

Mehrere Stringobjekte können das gleiche char[] verwenden (sharing)

Selbst ein leerer String braucht mehr als 24 bytes wenn das leere char[] nicht gemeinsam verwendetwird.

11

Diese Werte beziehen sich auf eine SUN JVM für 32 bit Intel Prozessoren. Bei anderen JVM‘s oderanderen Prozessoren kann der Speicherverbrauch anders aussehen.

12

Unter 64 bit braucht eine Java Applikation signifikant mehr Speicher als unter 32 bit, weil Referenzen8 Byte statt 4 Byte benötigen. Der Unterschied im Speicherverbrauch hängt daher vor allem davon abwieviele Referenzen es gibt.

Bei identischer Hardware (Speichergröße) bringt der Übergang auf 64 bit daher zunächst oft keinenPerformancegewinn. Allerdings ist unter 32 Bit Windows die maximale Größe des Java Heaps aufnicht viel mehr als 1 Gbyte beschränkt (etwas mehr unter Linux und bis zu 3,8 Gbyte unter Solaris).

13

In diesem vereinfachten Beispiel können folgende Schlüsse aus den Daten gezogen werden :

Es wird am meisten Speicher in char[] verbraucht

Die Anzahl der String Objekte ist etwas kleiner als die der char[]. Es wird aus den Daten nicht klar obdie vielen String Objekte char[] „sharen

Es ist nicht klar ob möglicherweise com.erp.Order viele Stringobjekte referenziert und dadurchletztlich den hohen Speicherverbrauch verursacht

14

Da die shallow size in der Praxis nicht sehr nützlich ist, braucht man ein Maß für die Menge desSpeichers die festgehalten wird.

Dazu simuliert man einen GC Lauf unter der Annahme, das eine bestimme Menge von Objekten nichtmehr existieren würde.

15

Hier ist ein Beispiel der LinkedList Klasse aus dem JDK dargestellt

16

17

18

Ein Heap Dump ist ein File, dass alle „noch lebendenden“ Java Objekte zu einem bestimmtenZeitpunkt enthält.

„Noch lebenden“= Erreichbar

Genaugenommen kann ein Heap dump auch noch Objekte enthalten, die nicht mehr referenziertwerden. Im Allgemeinen werden diese Objekte von den gängigen Heap dump Analyse Toolsallerdings nicht betrachtet.

Vor einem Heap dump wird ein Full GC ausgelöst.

19

Dies gilt zumindest für die SUN/SAP JVM.

Andere JVM‘S (IBM) schreiben Heap Dumps, die einige Informationen nicht enthalten

20

Es gibt einige verschiedene Möglichkeiten einen Heap dump zu erzeugen

21

Die Option

22

23

Das IBM Heap Dump Format wird durch ein zusätzliches Plugin unterstützt

MAT kann sowohl standalone als auch innerhalb von Eclipse benutzt werden

24

Wichtige Funktionen

Class histogramm

Show object

Retained size

Retained set

25

26

Objekte mit großer retained Size in einem großen Heap Dump mit Millionen von Objekten zu findenist manuell sehr schwierig.

Ein naiver Algorithmus um die größten Objekte zu finden,könnte für jedes Objekt im Heap eineSimulation einer Garbage Collection durchführen. Dies würde allerdings O(n^2) Aufwand bedeuten.Nimmt man z.B. 5 Sekunden für eine GC Simulation an und hat einen Heap mit 10 MillionenObjekten so bräuchte man mit diesem Algorithmus schon mehr als 1,5 Jahre. Außerdem hätte mandamit noch nicht die Information über die immediate Dominatoren der Objekte.

Der durch die immediate Dominatoren aufgespannte „Dominator tree“ erlaubt es unter anderem dieretained Size aller Objekte vorzuberechnen und der Größe nach zu sortieren.

Der Dominator Tree kann in „fast“ O(n) (O(m*agr;(m, n); agr == Inversion der Ackermannfunktion) Zeitmit dem Lengauer Tarjan Algorithmus (http://portal.acm.org/citation.cfm?id=357071&dl=GUIDE,)berechnet werden.

27

Das Business Objekt vom Typ com.myerp.buyer.Order referenziert einen LinkedList die StringObjekte enthält.

LinkedList$Entry2 ist der immediate Dominator von String 2

28

Der Immediate Dominator von LinkedList$Entry2 ist LinkedList$Entry0.

LinkedList$Entry1 ist kein Dominator von LinkedList$Entry2, da beim Entfernen vonLinkedList$Entry 1 weiterhin eine Referenz von

LinkedList$Entry0 auf LinkedList$Entry 2 besteht.

29

Durch die immediate Dominator‘s wird ein Baum aufgespannt (== Dominator tree).

30

Das com.myerp.buyer.Order Objekt „domiert die 3 String Objekte. Das heißt, dass wenn man dieseObjekt aus dem Speicher entfernen würde dann würde der GC auch die 3 Strings freigeben. Daß sichdazwischen eine Java Collection Klasse befindet ist für die Analyse meist nicht von Interesse. Es kanndaher nützlich sein im Dominator Tree Knoten herauszufiltern. Typischerweise möchte man Instanzenvon Java Standard library Klassen herausfiltern.

31

Wichtige Funktionen

Dominator Tree

Immediate Dominators

Top Consumers

32

33

Im Eclipse Debugger kann man dies leicht nachvollziehen. Der Grund für dieses Verhalten istdie effiziente Implementierung von StringBuffer.toString(). Diese kopiert nämlich das internechar[] des StringBuffer‘s nicht sondern verwendet es für den neu erzeugten String (unter JDK1.4).

34

Im Eclipse Debugger kann man dies leicht nachvollziehen. Der Grund für dieses Verhalten istdie effiziente Implementierung von StringBuffer.toString(). Diese kopiert nämlich das internechar[] des StringBuffer‘s nicht sondern verwendet es für den neu erzeugten String (unter JDK1.4).

35

Dieses Verhalten ist so gewollt. Der Vorteil ist dass mehrere String Objekte sich ein char[]teilen können.

36

37

XML DOM Bäume brauchen sehr viel Speicher, und sollten daher nicht direkt alsDatenstruktur verwendet werden.

Wenn der XML Parser alte Daten referenziert wird unnötig Speicher verbraucht.

XSLT Transformerobjekte können mehrere Mbyte verbrauchen. Da die Transformerobjekterelativ teuer zu erzeugen sind kann man durch Pooling versuchen immer nur einen begrenzteZahl im Speicher zu halten.

38

Caches sind relativ aufwendig zu implementieren, da nicht nur der Cache selberimplementiert werden muss sonder auch die Infrastruktur zum Monitoring und zurAdministration. Daher sollte man auf eine existierende stabile Cacheimplementierungzurückgreifen.

Ist eine Webseite „stateless“, kann also der Inhalt der Seite nur aus den Parametern desRequest berechnet werden, so kann sie auch gut vom Browser gecached werden.

39

Es gibt einige Strategien zur Minimierung des Speicherverbrauchs. Hier nur die wichtigsten.

Der Memory Analyzer bietet z.B. Queries für das finden leerer Collections an.

40

41

Die Klasse java.util.concurrent.CopyOnWriteArrayList (ab JDK 1.5) verwendet dieseStrategie

42

4343

44