Problem: I replaced my Windows 10 computer with a new Windows 11 one. On W10 I usually see a throughput to my Synology NAS of close to 1 Gbit/sec. On W11 the throughput was ways slower: I only got ~300 Mbit/sec when copying to/from the Samba Share.
Continue reading How to fix: slow network speed with Windows 11 to local NAS via Samba / SMB ShareTag: Performance
How to fix: IntelliJ IDEA and Scala being awfully slow on Windows 8.1
At work we are working mostly in Scala and most of us are using IntelliJ IDEA for coding. The choice of the operating system is up to the developer. As I am quite convenient with Windows (and use MS Office quite often), I am a happy Windows 8.1 user (btw: who the hell needs a start button when you have the windows key!? Anyways … different story).
The Problem
After a while when I started a Scalding project, IntelliJ became very slow and often turned to be non responsive for some seconds about once per minute. So over all it was a very inconvenient and unproductive situation.
Continue reading How to fix: IntelliJ IDEA and Scala being awfully slow on Windows 8.1
How to create Memory Leaks by using Inner Classes.
The most recent Java Specialists Newsletter finally convinced me to start this post that I was having in mind for quite some time.
One of the really huge advantages of Java is that you almost do not have to care about cleaning up your memory as the Garbage Collector usually does this for you as soon as Objects are no more referenced. Usually this works really really well so that you really don’t have to care about annything! But maybe once in a while you may be observing something like a memory leak. Some people then call the Garbage explicitly – which is usually just a bad idea and possibly also doesn’t help either so that the “leak” remains. The better solution in this case would be profiling so that you can see why some classes are not cleaned up.
A nice source for memory leaks can be the use of anonymous inner classes. Assume the following class where you want to compute s.th and return a Result-Object which derives from an Interface:
interface Result{} class Outer { int[] data = null; public Outer(int s) { data = new int[s]; } Object getResult() { return new Result(){}; } }
So if you call new Outer(1).getResult()
, you will still have an instance of Outer
in memory even though you did not keep an explicit reference. As explained in the Java Specialists Newsletter, each instance of an anoymous inner class always keeps a reference to the outer class! This is not a big deal as long as
- you don’t keep a lot of data in the
Outer
instance or - if the lifetime of the Result object is not long or
- if you won’t create a lot of results anyways.
Let’s have an example. If you execute
ArrayList l = new ArrayList(); int i = 0; while(true){ l.add(new Outer(0).getResult()); System.out.println(i++); }
with the above classes without memory constraints (-Xmx), this will run for quite some time because you are only holding 2 class references (Outer
, Result
) 1 field (the emtpty data array) and an implicit reference from Result
to Outer
. Which makes a total of 48 bytes on my Win7 64bit machine (according to this measurement).
Now change the parameter in the constructor of Outer
from 0 to 100000 and execute the code again. In my case I am getting an OutOfMemoryException after a bit more than 2000 created instances as now suddenly each iteration consumes 400.048 bytes (48 bytes as before + 100.000*4 bytes for the int-array) even though we only keep the explicit reference to the Result objects!
So – if you are creating an inner class the next time – you might have a brief look at the outer class as well and think about memory consumption and lifetime.
Performanceanalyse mit JVisualVM – evil synchronized
In einem meiner kleinen Projekte werden an einer Stelle etliche Threads gestartet, die jeweils ein Bild einlesen, skalieren und wieder auf die Platte schreiben. – Die ganze Zeit hat mich schon das Gefühl beschlichen, dass das zu langsam läuft, untersucht hatte ich das bisher nur nie. Nachdem genau diese Funktionalität heute definitv zu langsam war, kam ich um eine Analyse wohl doch nicht mehr herum. Also erst mal untersuchen, was da vor sich geht:
- Programm gestartet,
- JVisualVM gestartet (zu finden im bin-Verzeichnis einer JDK-Installation),
- VisualVM auf das laufende Programm verbunden, und die Threads anzeigen lassen
- kritische Funktion im Programm gestartet
Und siehe da: die Threads werden gestartet, aber nur immer genau einer ausgeführt (siehe Bild). Alle anderen Threads die laufen sollten stehen auf “Monitor”. Das ist leicht daran zu erkennen, dass zwar alle PictureScaleWorker ausgeführt werden, aber niemals gleichzeitig alle grün (also im Running State) sind sondern immer nur einer. Na das sollte ja nicht so sein!
Aber was machen die eigentlich und worauf warten die? Also erst mal einen Thread Dump erstellen (Button oben rechts), vielleicht bringt der ja ein paar Infos:
Dann zu einem der betreffenden Threads scrollen und nachsehen, ob dort etwas auffällig ist.
Thread.State: BLOCKED (on object monitor)
at de.locked.gallery.utils.ImageUtils.read (ImageUtils.java:83)
Blocked on object monitor – das sieht nach einem synchronized aus. Und betreffende Zeile 83 ist tatsächlich synchronized – was ich bei einem der letzten Refactorings offenbar übersehen habe. Mittlerweile ist die Synchronisierung auf dieser Methode zum Glück nicht mehr nötig und ich kann die Einschränkung ohne Gewissenbisse entfernen. Und siehe da, auf einmal laufen auch alle Threads gleichzeitig, was auf 8 Kernen doch einen spürbaren Unterschied macht. – Willkommen im Multi-Core Zeitalter.
Ohne die JVisualVM wäre ich früher oder später wohl auch an die Stelle gekommen – aber ich bezweifle ernsthaft dass ich die Stelle innerhalb weniger Minuten gefunden hätte.
Dazu auch ein interessantes Video.
System.gc() – gut gemeint, aber meist unnötig
Vor ein paar Tagen durfte ich mal wieder einen Blick in Fremdcode werfen, um zu sehen, wie die entsprechende Implementierung realisiert wurde. Eine an sich recht übersichtliche Methode, endete dann mit einem System.gc();
. Die Intention ist schon klar: “Gib bitte all den Speicher frei, der jetzt noch durch herrenlose Objekte belegt wird.” Das ist zwar gut gemeint, aber im Regelfall erstens unnötig und zweitens oft sogar kontraproduktiv.
Zu den Fakten. Als erstes sollte an der Stelle ein Blick in die API von System.gc()
folgen:
Calling the
gc
method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.
Das heißt die API impliziert hier schon, dass man sich nicht darauf verlassen kann und soll, dass nach dem Aufruf überhaupt irgendetwas passiert ist. (Die nächst schlimmere Lösung, die ich auch ab und zu gesehen habe, ist dann eine Schleife, in der der GC X-mal aufgerufen wird.)
Auf Stackoverflow findet sich eine interessante Diskussion, ob und warum der GC-Aufruf keine gute Idee ist – bzw WANN es eine gute Idee ist, den Aufruf wirklich zu machen. Ein kleines Fazit der ganzen Diskussion:
- Es wird oft gesagt, dass es Bad-Practice ist, also lass es (naja okay, kein gutes Argument)
- Die JVM kennt viele GCs, man weiß zur Ausführungszeit gar nicht, welcher GC aktiviert ist und wie er konfiguriert ist. Einfach mal auf der Java HotSpot VM Options nach “garbage collection” suchen.
- Die sinnvollere Art den GC zu konfigurieren ist nicht ihn einfach aufzurufen sondern ihn zu konfigurieren.
- Je nach Implementierung, kann ein Stop-The-World passieren. Also dass das gesamte Programm zur Garbage Collection steht.
- Eventuell geschieht auch gar nichts: http://bugs.sun.com/view_bug.do?bug_id=6668279
- Die Speicherverwaltung in der JVM ist nicht nur in Stack und Heap unterteilt. Der Heap ist unterteilt in Heap,Young,Tenured und Perm generation. Sun hat viel Zeit in die intelligente Garbage Collection gesteckt. Wenn man sich nicht mit Speicher Verwaltung und Garbage Collection beschäftigt, macht man es wahrscheinlich weniger intelligent als die Automatik.
- Oracle/Sun schlägt im Tuning Guide “Tuning the Java Runtime System” explizit vor, den Aufruf auszuschalten.
- .. und vermutlich noch einige weitere Argumente.
Wann es dann wirkliche eine gute Idee ist, den garbage collect selbst aufzurufen, ist dort auch zu lesen. Unter anderem, ist ein manueller GC sinnvoll wenn:
- Wenn man ein Speicherleck finden will, kann es sinnvoll sein, zu bestimmten Checkpunkten die Garbage Collection zu forcieren (oder es zu versuchen)
- Wenn man den Speicherverbrauch von Klassen bestimmen will (siehe Posting).
- Nach einer umfangreichen und langen Initialisierungsphase ist die Tenured-Generation vermutlich voll mit Objekten, die man nicht mehr brauchen wird und die man gleich aufzuräumen will/muss, um zu verhindern, dass der erste spätere GCs lange braucht, da dort enorm viele Objekte herumlungern die schon lange nicht mehr gebraucht werden.
- Nach einer kurzen Initialisierungsphase sind eventuell viele – später nicht mehr benötigte – Objekte im Speicher, die gar nicht erst in die Tenured Generation wandern sollen.
Interessante Links zum Thema:
- Diskussion bei Stackoverflow
- Warum es manchmal sinnvoll sein kann, den GC selbst auszulösen
- Chapter 4: Tuning the Java Runtime System
- What happened internally (JVM) when System.gc() or finalize() method called?
- Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine
- Java Performance:Garbage CollectionWie funktioniert Garbage Collection?
Speicherverbrauch in Java oder “Size does matter!”
Eines der Vorurteile gegenüber Java ist ja der (angeblich) enorme Speicherverbrauch. Frage ich dann, ob denn die entsprechende Applikation schon mal auf Speicherverbrauch geprofiled wurde und welcher Profiler verwendet wurde, gibt es große Augen und Gestammel über HeapSize, OutOfMemoryExceptions und dass in C ja eh alles besser sei. Na, da weiß man doch gleich dass nicht nur Java schuld sein muss. – Hat man mal mit ImageJ gearbeitet, ist man ab und an schon äußerst verwundert, wie schnell Java sein kann – und fühlt sich auch angespornt seine eigenen Kenntnisse zu erweitern.
Generell gibt es zur Speicherdiskussion (mindestens) zwei Szenarien.
- Die Diskussion, wieviel Speicher eine Datenstruktur verbraucht und ob nicht eine andere Speicherstruktur besser ist.
- Wir haben eine OOME und müssen sie beseitigen.
Wieviel Speicher verbraucht meine Datenstruktur?
DAS ist jetzt mal wirklich ein Nachteil von Java wie er im Buche steht, denn es gibt per se keine wirklich einfache Möglichkeit, den Speicherverbrauch einer Struktur oder eines Objektes zu ermitteln. Der Artikel From Java code to Java heap ist hier definitiv anzuraten. Hier wird detailierter über den Speicherverbrauch von Klassen eingegangen.
Im Java Specialists Newsletter von 2001(!!) gibt es einen einen Workaround und ein paar weitere Erklärungen – es folgt eine teils Übersetzung aus dem Newsletter:
- Jede Klasse belegt mindestens 8 Bytes auf dem Heap (also auch ein
new Object()
). - Jeder Datentyp belegt 4 Bytes, außer long und double, die 8 Bytes belegen. Achtung, das heißt, auch ein Datentyp byte benötigt dann 4 Bytes. Außerdem wird der Speicherverbrauch nur in 8 Byte Schritten erhöht. D.h eine Klasse mit einem byte Datentyp belegt 8 Byte für die Klasse + 8 Byte für die Daten = 16 Byte.
- Arrays sind speicherschonender – der geneigte Leser darf das gerne selbst nachlesen.
- String#intern() kann ordentlich Speicher sparen.
- Boolean.TRUE und Boolean.FALSE benötigen weniger als new Boolean(true).
Okay, alles schön und gut. Aber eine komplexere Struktur benötigt dann wieviel genau? Im Java Specialists Newsletter ist dazu eine kleine aber feine Klasse, die hier weiterhilft:
public class MemoryTestBench { public long calculateMemoryUsage(ObjectFactory factory) { Object handle = factory.makeObject(); long mem0 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); long mem1 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); handle = null; System.gc();System.gc();System.gc(); System.gc();System.gc();System.gc(); System.gc();System.gc();System.gc(); System.gc();System.gc();System.gc(); mem0 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); handle = factory.makeObject(); System.gc();System.gc();System.gc(); System.gc();System.gc();System.gc(); System.gc();System.gc();System.gc(); System.gc();System.gc();System.gc(); mem1 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); return mem1 - mem0; } public void showMemoryUsage(ObjectFactory factory) { long mem = calculateMemoryUsage(factory); System.out.println(factory.getClass().getName() + " produced " + factory.makeObject().getClass().getName() + " which took " + mem + " bytes"); } }
Die ObjectFactory sieht so aus:
public interface ObjectFactory { public Object makeObject(); }
Und am Beispiel einer ByteFactory sieht das wiederum so aus:
public class ByteFactory implements ObjectFactory { public Object makeObject() { return new Byte((byte)33); } }
Jup, etwas aufwändig. Aber immerhin ein Ausweg aus dem Dilemma um hypothetische Diskussionen was wohl besser sein könnte. Und ja, DAS ist in C wirklich einfacher – und trotzdem will ich weiter Java verwenden 😀
OMG, OOME – was tun?!
Regel 1: NICHT blindwütig irgendwo irgendwas irgendwie anders machen.
Regel 2: Auch nicht nachdenken und glauben zu wissen wo es weh tut.
Sondern? Messen!
Zum Beispiel mit der JVisualVM, die bei neueren SUN/Oracle JDKs (nicht JRE) bereits im bin-Verzeichnis der JVM mitgeliefert wird. Ist man eh mit NetBeans unterwegs, kann man das Programm auch nochmal von dort direkt profilen. Ich persönlich setze den erlaubten Speicher (also -Xmx) dann gleich kleiner an, damit die OOME schneller eintritt und weniger Daten betrachtet werden müssen.
Mit etwas Glück sieht man dann recht schnell, welche Datenstrukturen (zu) oft im Speicher sind und kann dann gezielter nach den Referenzen suchen, die es eigentlich gar nicht geben sollte.
LinkedList 33x schneller als ArrayList oder “Kenne deine API!”
Für meine Arbeit schreibe ich zum Test gerade ein kleines Plugin für ImageJ, indem ich unter anderem einen Region-Fill Algorithmus brauche – leider tut’s der filler von ImageJ hier nicht – also schnell was selbst zusammengehackt:
Startpunkt initialisieren und in eine Liste damit
while (Liste nicht leer) {
hole ersten Punkt P aus der Liste
prüfe Eigenschaften von p.x/p.y auf dem Bild
if (Eigenschaften erfüllt){
füge der Liste die Punkte darüber, darunter, rechts und links hinzu
}
}
Vorher eine ArrayList entsprechend groß initialisiert, damit die nicht dynamisch wachsen muss und gut ist’s.
Moment – in vielen Iterationen werden hinten an der Liste 4 Punkte angefügt. Das geht mit der ArrayList schön schnell, wie man im ArrayList Quellcode unschwer erkennt (wenn die Liste groß genug ist). Aber in jeder Iteration wird vorne das erste Element entnommen. – Ein Blick in den ArrayList-Quellcode offenbart ein “System.arraycopy(elementData, index+1, elementData, index, numMoved);“. Oha – das riecht eigentlich eher nach einer LinkedList.
Also: Methode profilen, Listentyp ändern, nochmal profilen (mit dem NetBeans Profiler ja kein Thema). Ergebnis: LinkedList ist wie erwartet viel schneller. Ohne meinen ganzen sonstigen Code reduziert sich der Testfall in etwa auf folgende Testklasse:
public class ListTest {
public static void main(String[] args) {
List al = new ArrayList(31000);
List ll = new LinkedList();
long a = System.currentTimeMillis();
testWith(al);
long b = System.currentTimeMillis();
testWith(ll);
long c = System.currentTimeMillis();
System.out.println("ArrayList: "+(b - a) + " ms");
System.out.println("LinkedList: "+(c - b) + " ms");
}
private static void testWith(List list) {
list.add(new Point(0, 0));
int i = 10000;
Point p;
while (!list.isEmpty()) {
p = list.remove(0);
if (i-- > 0) {
list.add(new Point(p.x, p.y - 1));
list.add(new Point(p.x - 1, p.y));
list.add(new Point(p.x + 1, p.y));
list.add(new Point(p.x, p.y + 1));
}
}
}
}
Das Speedstepping am Notebook nicht vergessen, sonst fährt die CPU am anfang ja noch nicht auf Vollgas und schon rennt der Test. Die ArrayList habe ich auch extra noch mit mehr Elementen initialisiert, als jemals reinkommen. Ausserdem geht die Initialisierung auch nicht in die Messung ein (ist im Vergeich mit dem Rest zwar eh vernachlässigbar klein, aber damit niemand auf die Idee kommt, der Vergleich wäre unfair …).
Ausgabe:
ArrayList: 860 ms = 100%
LinkedList: 31 ms = 3,6%
Sieht man sich die API und den Quellcode der beiden Klassen an, verwundert das Ergebnis nicht wirklich. Der unterschied skaliert natürlich auch mit der Anzahl der Iterationen.
Fazit
Ist ArrayList also schlecht? – Klares NEIN! Nur für genau diesen Anwendungfall (vielfaches Einfügen am Ende, vielfaches Herausnehmen am Anfang, kein Zugriff auf Elemente irgendwo dazwischen nötig) ist die ArrayList der Speicherstruktur der LinkedList einfach unterlegen, die genau auf diesen Punkten optimal funktioniert.
Ergo: Know your API! Man sollte sein Handwerkszeug kennen und nicht blindlings einfach das verwenden was man sonnst auch immer nimmt und hoffen, dass Java ein allmächtiges Werkzeug ist, das einem alle Arbeit abnimmt (und dann nacher groß jammern, dass in C++ ja eh alles viel schneller geht). Und wenn man Zweifel hat, ruhig mal einen Blick in den Sourcecode werfen und ausprobieren 😉
Java Memory Model / MultiThreading in Java
Wer sich für das Java Memory Model und insbesondere für Multi Threaded Code und die Probleme mit denen man sich konfrontiert sieht, wenn man multi threaded programmiert interessiert, könnte das Video durchaus interessant finden.
Titel: Advance Topics in Programming Language: Java Memory Model
von Jeremy Manson
[youtube=http://www.youtube.com/watch?v=1FX4zco0ziY]
Java Heap-Implementierung / Avoid too much sorting II
Im Artikel Avoid too much sorting habe ich ja schon kurz skizziert, dass man es generell vermeiden sollte seine Daten unnötig oft zu sortieren, weil das einfach (je nachdem wie oft der entsprechende Code aufgerufen wird) ziemlich in die Rechenzeit gehen kann.
Manchmal muss man seine Daten aber eben sortiert halten. – Dann sollte man sich aber überlegen, ob man wirklich die ganzen Daten sortieren muss, oder ob es nicht einfach reicht, immer das kleinste/größte Element einer Menge zu bekommen. Ein gutes Beispiel ist zum Beispiel der altbekannte Dijkstra-Algorithmus. Dort benötigt man in jeder Iteration z.B. den Weg mit den bisher kleinsten Kosten.
Das schreit ja schon nach Sortieren. Bzw. eigentlich sollte einem da gleich die Heap-Datenstruktur einfallen, da dort alle Operaionen maximal in O(log n) erledigt sind, und nicht (wie beim Sortieren) in bis zu O(n²). Das schöne daran ist, dass es das in Java auch schon gibt, da heißt es nur nicht Heap (da man dabei vermutlich zu sehr an die Speicherverwaltung denken könnte), sondern PriorityQueue.
Wenn man jetzt aber Objekte sortieren will die nicht per se Comparable sind, benötigt man noch eine kleine Comparator-Implementierung mit einem SimpleEntry, damit man einem beliebigem Objekt auch seine Kosten zuweisen kann. Klingt jetzt recht aufwändig – ist es aber bei weitem nicht:
import java.util.AbstractMap.SimpleEntry;
import java.util.Comparator;
import java.util.PriorityQueue;
public class Test {
public static void main(String[] args) {
PriorityQueue<SimpleEntry> heap =
new PriorityQueue<SimpleEntry>(10, new FooCmp());
heap.add(new SimpleEntry(1d, new Foo(1)));
heap.add(new SimpleEntry(5d, new Foo(2)));
heap.add(new SimpleEntry(2d, new Foo(3)));
while (!heap.isEmpty()) {
System.out.println(heap.poll().getValue().i);
}
}
}
class FooCmp implements Comparator<SimpleEntry> {
@Override
public int compare(SimpleEntry o1, SimpleEntry o2) {
return Double.compare(o1.getKey(), o2.getKey());
}
}
class Foo {
int i;
Foo(int i) { this.i = i; }
}
JXMapKit: Karten schneller und gleichzeitig laden
Verschiebt man die Karte eines JXMapKit, müssen ja logischerweise Kartenteile (Kacheln) nachgeladen werden.
Per Default werden immer nur 4 Kacheln gleichzeitg geladen. Bei entsprechend schneller Verbindung macht es durchaus Sinn, diese Zahl zu erhöhen:
((AbstractTileFactory) jXMapKit.getMainMap().getTileFactory()).setThreadPoolSize(10);
Und schon wird spürbar schneller nachgeladen. Allerdings muss der Aufruf durchgeführt werden, bevor die erste Kachel geladen wird, wie die Javadoc aussagt:
/** * Set the number of threads to use for loading the tiles. This controls the number of threads * used by the ExecutorService returned from getService(). Note, this method should * be called before loading the first tile. Calls after the first tile are loaded will * have no effect by default. * @param size */
Siehe auch: “Erste Schritte mit JavaX JXMapKit“