Unser Index hatte eine Größe erreicht, bei der ein Optimize zu einer OutOfMemoryException führte.
Der wesentliche Teil der Catalina.out gab dabei Folgendes aus:
Caused by: java.lang.OutOfMemoryError: Map failed
>>> at sun.nio.ch.FileChannelImpl.map0(Native Method)
>>> at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:762)
Als ersten Versuch haben wir den RAM für die JVM höher gesetzt, allerdings mit dem zunächst verwirrenden Ergebnis, dass die OOE noch schneller geworfen wurde als zuvor.
Nach etwas Recherche ließ sich feststellen, dass die nio-Klasse außerhalb des Speichers der JVM wildert und folgedessen eine entsprechende Erhöhung eher Kontraproduktiv ist, da der nun von der JVM zusätzlich verwendete Speicher dem OS und damit der bio-Klasse fehlt.
Letztendlich lässt sich das Problem einfach in den Griff bekommen. Man muss lediglich der Shell, in welcher die JVM läuft, per 'ulimit -v unlimited' genügend virtuellen Speicher zur Verfügung stellen. Normalerweise sollte es reichen, den ulimit-Befehl in jenes Init-Skript zu schreiben, mit welchem man die JVM, den Tomcat, Jetty - was auch immer - startet.
Wenn man wissen möchte, wie hoch der zur Verfügung stehende virtuelle Speicher von Hause aus ist, dann hilft ein 'ulimit -v'. Und man darf sich nicht täuschen lassen - wir hatten einen Vmem von ~14GB und unser Index hatte "nur" 5GB. Das sollte locker ausreichen, möchte man meinen. Tat es aber nicht. Bei einem Optimize landet man sehr schnell bei sehr hohem Speicherverbrauch.
Entscheidend ist, dass der ulimit-Befehl in jener Shell ausgeführt wird, in welcher die JVM läuft, denn ulimit scheint per se nur in der Shell zu gelten, in welcher er ausgeführt wurde.
Entscheidend ist, dass der ulimit-Befehl in jener Shell ausgeführt wird, in welcher die JVM läuft, denn ulimit scheint per se nur in der Shell zu gelten, in welcher er ausgeführt wurde.