"Segmentation fault" Virtual Machine Konfiguration Großrechner?

sunny01

Aktives Mitglied
Hallo,

ich hoffe, ich bin hier richtig.

Folgendes Problem: Ich muss auf einem Großrechner, auf den ich nur per SSH Zugriff habe, ein Java-Programm laufen lassen, das als eine Art Webspider fungiert. Das Ganze ist natürlich relativ speicherintensiv. Ich bekomme nun bei etwa 6.000 Knoten (die Knoten sind die Links auf Unterseiten der Website, die jweils im Speicher gehalten werden bis eine Website intern komplett abgearbeitet ist) immer obenstehenden "Segmentation fault" Fehler.

Durch Googeln habe ich herausgefunden, dass es sich hierbei wahrscheinlich um ein Speicherzugriffsproblem handelt. Nun kann man ja mittels Parametern den Speicher für die Virtual Machine erhöhen (Xss, Xms, Xmx). Auch habe ich etwas gelesen von limit und ulimit unter Linux. Allerdings weiß ich jetzt nicht so recht, wie und was ich machen muss, um mein Problem zu lösen (habe weder mit Linux noch mit VM-Konfiguration, Konsole etc. Erfahrung).

Kann mir hier jemand weiterhelfen?
Weiß jemand, was ich (genau) machen muss, um den Fehler zu beseitigen?

Ich versuche ein paar Informationen über benannten Großrechner zur Verfügung zu stellen, weiß aber nciht so recht, was hier relevant ist, um die korrekten Einstellungen/Parameter für die Virtual Machine herauszubekommen. Leider kann ich nciht einfach "herumprobieren", da es ja immer ziemlich lang dauert, bis der Fehler dann irgendwann einmal kommt.


~$ cat /proc/version
Linux version 2.6.28-11-generic (buildd@crested) (gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4) ) #42-Ubuntu SMP Fri Apr 17 01:58:03 UTC 2009

~$ cat /proc/meminfo
MemTotal: 65309840 kB
MemFree: 29487156 kB
Buffers: 384976 kB
Cached: 11008768 kB
SwapCached: 0 kB
Active: 26689504 kB
Inactive: 8771820 kB
Active(anon): 24073680 kB
Inactive(anon): 0 kB
Active(file): 2615824 kB
Inactive(file): 8771820 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 2963952 kB
SwapFree: 2963952 kB
Dirty: 116 kB
Writeback: 0 kB
AnonPages: 24067480 kB
Mapped: 69684 kB
Slab: 235956 kB
SReclaimable: 205944 kB
SUnreclaim: 30012 kB
PageTables: 69540 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 35618872 kB
Committed_AS: 23683016 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 2004 kB
VmallocChunk: 34359735679 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 10584 kB
DirectMap2M: 67096576 kB

~$ java -version
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode)


Habe schon sehr viel gegoogelt aber finde nicht heraus was ich konkret tun kann ... ich hoffe jemand hier hat vielleicht Erfahrung mit solchen Dingen.

Liebe Grüße
sunny
 

FArt

Top Contributor
Ich weiß zwar nicht was fehlt, aber wir können uns ja der Sache nähern.. ;-)

Unter welchem JDK ist die Applikation kompiliert worden?
Bricht die VM ab, wenn der Fehler kommt? Gibt es dann einen Dump? Läuft die Applikation fehlerfrei auf anderen Rechnern, Betriebsystemen bzw. Architekturen, Versionen der virtuellen Maschine? Benutzt die Applikation native Komponenten (JNI oder Datenbanktreiber)?

Segmentation Fault ist normalerweise nicht der Fehler, wenn der Speicher lediglich ausgeht, sondern eine Schutzverletzung beim Zugriff auf bestimmte (geschütze) Speicherbereiche.
 

sunny01

Aktives Mitglied
Guten Morgen!

Ich weiß zwar nicht was fehlt, aber wir können uns ja der Sache nähern.. ;-)

Ui ... hoffentlich ...
Ich versuche mal Deine Fragen zu beantworten:

Unter welchem JDK ist die Applikation kompiliert worden?
Die JDK Version ist 1.6.0_20.
Das JAR wurde mit Netbeans 6.8 erstellt, unter Windows 7, falls das auch relevant ist.

Bricht die VM ab, wenn der Fehler kommt?
Ja leider ... das ist ja das Problem.

Gibt es dann einen Dump?
Hm, woher weiß ich das?
In der Konsole steht dann nur: "Segmentation fault". Nichts weiter.

Läuft die Applikation fehlerfrei auf anderen Rechnern, Betriebsystemen bzw. Architekturen, Versionen der virtuellen Maschine?
Also so viele derartige Großrechner habe ich nicht zur Verfügung.
Auf meinem Laptop läuft das Programm, allerdings kommt es irgendwann zu einem StackOverflow bzw. zu einem OutOfMemory. Das ist ja, neben der superschnellen Internetanbindung des Großrechners, der Grund, warum das Script dort laufen muss. Das Programm frisst recht viel Speicher, wenn große Webseiten durchgearbeitet werden. Es soll ein Graph erstellt werden pro Website, der die interne Linkstruktur abbildet. Schlussendlich werden Adjazenzmatrizen in Textfiles geschrieben. Bis es aber so weit ist, muss jede einzelne URL, die es in der Website mit ihren Unterseiten gibt, im Speicher gehalten werden, sodass ich prüfen kann, ob es ein neuer oder ein bereits besuchter Link ist. Es gibt also mehrere ArrayLists im Programm, die einerseits Knotenindizes verwalten und andererseits Strings (die URLs). Die Webseiten die so bearbeitet werden sollen, haben zum Teil > 20.000 Unterseiten.
(Das Textfile wird übrigens erst ganz am Schluss geschrieben, also erst, wenn eine Seite komplett durchgearbeitet ist, werden die Adjazenzlisten in eine Adjazenzmatrix umgewandelt und dann wird eine Textdatei geöffnet und geschrieben, diese bleibt also nicht während des gesamten Laufs offen oder dergleichen).

Benutzt die Applikation native Komponenten (JNI oder Datenbanktreiber)?
Eigentlich nicht. An externen Libraries sind in Verwendung: JDom und HTMLCleaner.

Segmentation Fault ist normalerweise nicht der Fehler, wenn der Speicher lediglich ausgeht, sondern eine Schutzverletzung beim Zugriff auf bestimmte (geschütze) Speicherbereiche.
Aber ich kann doch mit einem Java-Programm gar nicht auf irgendwelche geschützten Speicherbereiche zugreifen, oder? Also bisher habe ich auf dem besagten Rechner auch überhaupt keine weiteren Angaben zur VM-Speicherverwendung etc. gemacht, da ich mich ja wie gesagt damit gar nicht gut auskenne und da auch nicht irgendwie "herumprobieren" kann. Lokal bei mir habe ich zum Testen einfach der VM mehr Speicher gegeben (mit diesen X..-Parametern), das hat auch geholfen, aber nur bis zu einem gewissen Grad ... ist ja nur ein Personal Computer mit 3 GB und 32-Bit Windows ... Aufgrund der besseren Internetanbindung "muss" das Ding aber sowieso am anderen Rechner laufen. Auf meinem Rechner war nur die Entwicklung und das Testen, sozusagen.

Ich hoffe, Du kannst mir irgendwie weiterhelfen, ich bin in diesem Themengebiet völlig verloren ...

Offensichtlich hatt der Rechner mehr als 4GB RAM. Vielleicht gibt es da ein Durcheinander von 32 Bit und 64 Bit Packeten?
Ja der hat sehr viel mehr RAM. Aber was die Pakete betrifft, ich glaube, auf so etwas habe ich keinen Einfluss ... ich kann auf dem Rechner dort ja "nichts" machen, in dem Sinne ... außer mein JAR starten und eventuell irgendwas mit der VM, falls es da Möglichkeiten gibt, mein Problem anzugehen.
Ich weiß aber auch nciht so richtig woran es liegt. Sehr schwierig für mich ...

Danke für's Lesen erstmal, habe versucht es so gut wie möglich zu erläutern.

Lg
sunny
 
Zuletzt bearbeitet:

homer65

Top Contributor
Du kannst auch auf einem Großrechner mittels z.B. -Xms16m und -Xmx128m die Speicherzuordnung beeinflußen.
Wenn du dich nicht mit eurem Großrechner auskennst, so gibt es dort doch sicherlich einem Sysprog.
Was sagt der den?
 

sunny01

Aktives Mitglied
Der sagt ich soll nicht so viele blöde Fragen stellen weil man das alles im Internet herausfinden kann und er weitaus besseres zu tun hat :(
Bin nicht sicher, ob der überhaupt eine Ahnung hat, die Serververwaltung wurde ihm "aufgedonnert", soweit ich das mitbekommen habe.

Mir ist schon klar, dass ich diese Parameter auch mitgeben kann beim Start des JAR. Aber ich weiß eben überhaupt nicht, was ich da angeben könnte/sollte und ob das irgendwas bringt. Ich kann ja nicht einfach irgendwelche Werte ausprobieren, dann mal jeweils eine Stunde warten, und schauen ob es nun länger als bis ~6.000 Knoten läuft. So komme ich ja nie zu einem laufenden Programm ... daher hier meine Frage in der Hoffnung irgendjemand weiß was ich da so ungefähr tun sollte ...

Liebe Grüße
sunny
 

FArt

Top Contributor
Dass das Programm so viel Speicher benötigt, ist vermutlich ein grober Designfehler. Die gesamte Datenhaltung im Speicher ist wohl suboptimal. Eine Datenbank ist dafür besser geeignet und spart viel Speicher. Trotzdem solltest du den maximalen Speicher der VM ruhig recht hoch setzen (für den Echtbetrieb). Für die Testphase ist es u.U. besser den Speicher niedriger zu setzen: kommt dann der selbe Fehler oder "nur" ein OutOfMemory (und das entsprechend früher)?

Wenn die VM abstürzt, liegt in der Regel eine Fehlerdatei im aktuellen Verzeichnis hs_err_pid..... (vergleiche Crash course on JVM crash analysis | Java.net). Diese gibt Aufschluß darüber, was passiert ist. Oder liefert die VM einen Stacktrace und beendet sich mit einem Returncode ungleich 0?

Du kannst so eine Schutzverletzung in Java nicht direkt verursachen. Die VM (oder andere native Komponenten) verursachen diese implizit. Das kann durch einen Bug in der VM sein, durch einen Bug im Betriebsystem, durch eine inkompatible Kombination von Programmen und Betriebsystem usw. Ab und zu kommt es z.B. zu einem Bug im HotSpot-Compiler der VM. Nach vielen (tausend) Durchläufen durch einen Codeabschnitt, optimiert der Comiler diese Codestelle dann u.U. fehlerhaft, was nach längerer Laufzeit zu einem Fehler führt. Dann kann man z.B. die Klasse von der Optimierung ausnehmen.

Alles was an Fehlern in Java passiert fürht sonst nicht zu einem Programmabsturz sondern zu einer Exception, einem Error und evtl. zu einem Ende der VM nach der Fehlermeldung. Also irgendetwas sollte da sein (außer segmentation fault).

Wenn nichts zu finden ist: probiere das Programm unter anderen BS mit etwas Speicher aus... Windwos und Linux gibt es auf vielen Kisten und Speicher sollte zu finden sein. Variiere die JRE auf dem Großrechner. Nimm ruhig mal eine ältere 6er her oder auch eine 5er (vorher dein Programm unter JDK 5 kompilieren).
 
Zuletzt bearbeitet:

homer65

Top Contributor
Der sagt ich soll nicht so viele blöde Fragen stellen weil man das alles im Internet herausfinden kann und er weitaus besseres zu tun hat :(
Dann sag ihm doch mal, das er gefälligst seinen dicken Hinter bewegen soll und ein vernünftiges 64 Bit JDK installieren soll. :)

Außerdem ist es einen Versuch wert meine vorhin geposteten Werte mal auszuprobieren. Wenn du die Speicherzuordnung nicht zu groß wählst, kann es sein das das 32 Bit JDK trotzdem funktioniert.
 

sunny01

Aktives Mitglied
Dass das Programm so viel Speicher benötigt, ist vermutlich ein grober Designfehler. Die gesamte Datenhaltung im Speicher ist wohl suboptimal. Eine Datenbank ist dafür besser geeignet und spart viel Speicher.

Eine Datenbank soll ich gar nicht verwenden.
Allerdings war meinem Prof auch nicht klar, dass die Webseiten so riesig sind, die da ausgelesen werden sollen.
Ich habe auch schon die Rekursion entfernt, das Ganze läuft jetzt sequentiell ... dafür ist halt aber noch eine weitere ArrayList notwendig gewesen, die mir jeweils noch nicht besuchten Links in einer Liste hält.
Auf dem Großrechner läuft das Ganze aber auch richtig schnell, bis nur eben plötzlich auf einmal der "Segmentation fault"-Fehler kommt.

Trotzdem solltest du den maximalen Speicher der VM ruhig recht hoch setzen (für den Echtbetrieb). Für die Testphase ist es u.U. besser den Speicher niedriger zu setzen: kommt dann der selbe Fehler oder "nur" ein OutOfMemory (und das entsprechend früher)?
Welche Werte soll ich denn da sinnvollerweise probieren, bei so einer Rechnerkonfiguration?

Wenn die VM abstürzt, liegt in der Regel eine Fehlerdatei im aktuellen Verzeichnis hs_err_pid..... (vergleiche Crash course on JVM crash analysis | Java.net). Diese gibt Aufschluß darüber, was passiert ist. Oder liefert die VM einen Stacktrace und beendet sich mit einem Returncode ungleich 0?
Wie komme ich zu dieser Fehlerdatei bzw. zu dem Verzeichnis? Sorry, das ist das erste Mal dass ich etwas mit Linux und Konsolen usw. zu tun habe ...
Ich habe per SSH Zugriff auf ein eigenes Userverzeichnis ... mehr nicht. Kann ich dann trotzdem auf dieses Verzeichnis mit der Fehlerdatei zugreifen, und wenn ja, wie?

Wenn nichts zu finden ist: probiere das Programm unter anderen BS mit etwas Speicher aus... Windwos und Linux gibt es auf vielen Kisten und Speicher sollte zu finden sein. Variiere die JRE auf dem Großrechner. Nimm ruhig mal eine ältere 6er her oder auch eine 5er (vorher dein Programm unter JDK 5 kompilieren).

Also auf meinem Windows Rechner kommt kein Segmentation fault.
Wie ich die JRE auf dem Großrechner ändern kann, weiß ich leider auch nicht.
Es ist für mich einfach so schwierig, weil ich mich mit all' diesen Dingen nicht auskenne ...

Lg
sunny
 

sunny01

Aktives Mitglied
Dann sag ihm doch mal, das er gefälligst seinen dicken Hinter bewegen soll und ein vernünftiges 64 Bit JDK installieren soll. :)
Wenn das so einfach wäre ...

Außerdem ist es einen Versuch wert meine vorhin geposteten Werte mal auszuprobieren. Wenn du die Speicherzuordnung nicht zu groß wählst, kann es sein das das 32 Bit JDK trotzdem funktioniert.
Okay, ich mache das mal!

Hab mal geguckt:
Java-Downloads für alle Betriebssysteme - Sun Microsystems
Dort nach Linux suchen.
Dann Linux x64 auswählen.
Zum auf dem Server installieren? Kann ich das selber machen? Wohl kaum, oder doch?

Lg
sunny
 
G

Guest2

Gast
Moin,

~$ java -version
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode)

er nutzt doch eine 64Bit VM.


Ich hatte das Problem hier auch schon, dass statt einem OutOfMemory ein Segmentation fault flog. Versuchs doch einfach mal mit –Xmx32768m –Xms32768m und beobachte was passiert.

Gruß,
Fancy
 

sunny01

Aktives Mitglied
Warum nicht. Versuch macht klug.
Bin nicht sicher, ob ich dafür Rechte habe ... muss mir auch erst anschauen, wie man unter Linux irgendetwas installieren kann. Werde ich in der Zwischenzeit mal googlen.
Habe das JAR jetzt mal mit den von Dir geposteten Parametern gestartet. Mal sehen was passiert ...

er nutzt doch eine 64Bit VM.
Dachte ich eigentlich auch ...

Ich hatte das Problem hier auch schon, dass statt einem OutOfMemory ein Segmentation fault flog. Versuchs doch einfach mal mit –Xmx32768m –Xms32768m und beobachte was passiert.
Danke, ich werde das versuchen, falls es mit den aktuellen Werten mit denen das Programm gerade läuft, auch wieder abbricht.

Lg
sunny
 

homer65

Top Contributor
Außerdem kannst du mit JMX den Speicherverbrauch beobachten. Und evt. sogar einen Garbage Collect anstoßen.
Zitat aus unserem Wiki:
Man kann Java Batch Jobs unter z/OS mit JMX beobachten.
Hierzu haben wir das Profile /vwb/sysprog/profileJMX erstellt.
Dort werden die folgenden Optionen gesetzt:
IJO = "$IJO -Dcom.sun.management.jmxremote.port=9090"
IJO = "$IJO -Dcom.sun.management.jmxremote.authenticate=false"
IJO = "$IJO -Dcom.sun.management.jmxremote.ssl=false"
Da das Java Batch Programm am Port 9090 lauscht kann immer nur ein Programm mit diesem Profile laufen.
Unter Linux ruft man auf der Konsole den Befehl:
jconsole
auf. Dieser startet ein graphische Oberfläche, in der man unter dem Punkt "* Remote Process" folgendes einträgt:
10.1.252.25:9090
Mit jconsole kann man insbesondere den Memory Verbrauch beobachten und gegebenfalls den GarbageCollector anstoßen.
 

sunny01

Aktives Mitglied
Naja, wie gesagt, ich habe überhaupt keine Ahnung von Linux ... sorry Leute ... ich will auch eigentlich gar nichts installieren, wenn es nicht sein muss ... ich glaube, das hat sich ohnehin erübrigt, da ja ein 64bit JDK installiert ist.

Höchstens ich sollte tatsächlich noch das mit den älteren Versionen probieren, wie weiter oben vorgeschlagen ... aber ich weiß nicht so recht ... :noe:
Das bringt mich noch zur Verzweiflung alles ...
 

FArt

Top Contributor
Wenn man mal schnell was ausprobieren möchte, einfach eine Runtime per SCP kopieren und die Pfade in der Shell anpassen.

Sollte es tatsächlich nur daran liegen, dass der Speicher ausgeht (versuche das mit JConsole und/oder verschiedenen Konfigurationswerten für den maximalen Speicher der VM zu verifizieren), dann ist die schnellste Lösung: baue die speicherintensiven Collections so um, dass sie eine kleine DB verwenden (z.B. HSQL-DB) der Aufwand für so eine Umstellung sollte gering sein. Der Speicherbedarf wird drastisch sinken, die Performance zwar auch ein wenig, aber das sollte nicht so tragisch sein.
 

faetzminator

Gesperrter Benutzer
Das Original SUN JDK muss man von Hand installieren ;)

Er hat nur das JRE installiert und benötigt auch nur das JRE ;)
Aber man siehe...
Code:
[faetzminator@fkaros ~]$ apt-cache search sun-java6
sun-java6-source - Sun Java(TM) Development Kit (JDK) 6 source files
sun-java6-jre - Sun Java(TM) Runtime Environment (JRE) 6 (architecture independent files)
sun-java6-javadb - Java(TM) DB, Sun Microsystems' distribution of Apache Derby
sun-java6-fonts - Lucida TrueType fonts (from the Sun JRE)
sun-java6-plugin - The Java(TM) Plug-in, Java SE 6
sun-java6-jdk - Sun Java(TM) Development Kit (JDK) 6
sun-java6-demo - Sun Java(TM) Development Kit (JDK) 6 demos and examples
sun-java6-bin - Sun Java(TM) Runtime Environment (JRE) 6 (architecture dependent files)
ia32-sun-java6-bin - Sun Java(TM) Runtime Environment (JRE) 6 (32-bit)
 

sunny01

Aktives Mitglied
Wenn man mal schnell was ausprobieren möchte, einfach eine Runtime per SCP kopieren und die Pfade in der Shell anpassen.
Das sagt mir jetzt überhaupt nichts *schäm*

Sollte es tatsächlich nur daran liegen, dass der Speicher ausgeht (versuche das mit JConsole und/oder verschiedenen Konfigurationswerten für den maximalen Speicher der VM zu verifizieren), dann ist die schnellste Lösung: baue die speicherintensiven Collections so um, dass sie eine kleine DB verwenden (z.B. HSQL-DB) der Aufwand für so eine Umstellung sollte gering sein. Der Speicherbedarf wird drastisch sinken, die Performance zwar auch ein wenig, aber das sollte nicht so tragisch sein.
Also die Performance ist schon etwas problematisch, da ich bis nächste Woche die 500 Riesenseiten abgearbeitet haben sollte ... auch die Zeit für's DB-Installieren und Umprogrammieren fehlt (aber wenn es nicht anders geht, muss das wohl irgendwie gemacht werden) ... aber bei einem Rechner mit 62 GB RAM hätte ich jetzt auch nicht unbedingt damit gerechnet, dass da der Speicher ausgeht ... wenn es ja sogar bei mir lokal, zwar langsam, aber immerhin bis 8.500 Knoten problemlos durchläuft ... so weit kommt es auf dem Großrechner nicht mal ... da kam der Abbruch ja schon immer jeweils bei ca. 6.000 ... dafür war er halt nach 20 Minuten bei Knoten 6.000 angelangt, wofür mein lokaler Rechner mit normaler Internetanbindung ca. 10 h gebraucht hat ... ;(
 

sunny01

Aktives Mitglied
homer65, diese Parameter habe ich gerade ausprobiert ... bei Knoten 5.000 in etwa kam der Segmentation fault.

Wie funktioniert das mit der jconsole?

Habe versucht einfach in die Konsole jconsole einzugeben, aber es ist folgendes passiert:

~$ jconsole
Exception in thread "AWT-EventQueue-0" java.awt.HeadlessException:
No X11 DISPLAY variable was set, but this program performed an operation which requires it.
at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:159)
at java.awt.Window.<init>(Window.java:432)
at java.awt.Frame.<init>(Frame.java:403)
at javax.swing.JFrame.<init>(JFrame.java:202)
at sun.tools.jconsole.JConsole.<init>(JConsole.java:97)
at sun.tools.jconsole.JConsole$6.run(JConsole.java:770)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

Kann mir bitte jemand Schritt für Schritt sagen, wie das mit dem JMX bzw. der jconsole funktioniert, bzw. einen Link dazu posten?
 

faetzminator

Gesperrter Benutzer
Er muss das GUI irgendwo anzeigen, du hast aber nur eine Konsole. Du kannst beim Verbinden per SSH den Parameter [c]-X[/c] mitgeben - dein Client muss aber natürlich X11 unterstützen... (kann das z.B. Putty unter Windoof?)
 

homer65

Top Contributor
Ich hatte ja schon einen Auszug aus unserem Wiki gepostet.
JMX funktioniert über TCP/IP.
Beim Aufruf des Java Programms gibt du die geposteten Optionen mit.
Dann lauscht das Java Programm am mitgegebenen Port.
jconsole kannst du von jedem beliebigen Rechner aufrufen, der eine TCP/IP Verbindung zum Großrechenr hatt.
Du mußt natürlich die IP adresse kennen.
Direkt per ssh funktioniert es wohl nicht, da du keinen X Server hast.
Hast du evt. ein PC Linux zur Verfügung, wo du jconsole aufrufen kannst?
 

FArt

Top Contributor
Verifziere ob wirklich der Speicher auszugehen scheint.
Schau dir den Speicherverlauf mit JConsole an und/oder starte die VM mit den Parametern (probiere mal verschiedene aus):
-Xloggc:datei ---> um zu sehen, was der GC so treibt
-XX:ErrorFile=./hs_err_pid<pid>.log --> um auf jeden Fall bei einem Fehler einen Hinweis zu bekommen
-XX:+HeapDumpOnOutOfMemoryError --> schreibt einen HeapDump wenn der Speicher ausgeht
-XX:+PrintGCDetails --> nomen est omen
-XX:+PerfSaveDataToFile --> habe ich noch nicht ausprobiert

Weiteres: Java HotSpot VM Options
 
G

Guest2

Gast
homer65, diese Parameter habe ich gerade ausprobiert ... bei Knoten 5.000 in etwa kam der Segmentation fault.

Jetzt werd ich neugierig. :D

Magst / Kannst Du deinen Code zeigen?

(Wüsste nicht wieso 5000 Knoten nicht in 32GB passen sollten...)

Und hast Du mal nachgesehen (in dem Verzeichnis wo Du java... eintippst) ob eine hs_err* vorhanden ist (mit ls)?


Gruß,
Fancy
 

sunny01

Aktives Mitglied
Es tut mir leid Leute ... ich kenne mich überhaupt nicht mehr aus. Das ist zu viel Information, ich weiß nicht mehr was wo hin gehört und was ich jetzt eigentlich machen soll. Ich fühle mich wie der letzte Idiot weil ich einfach keine Ahnung von Linux und diesen ganzen Dingen habe. Ihr helft mir so viel aber ich weiß einfach überhaupt nicht mehr weiter ...
 

sunny01

Aktives Mitglied
Fancy,

selbstverständlich kann ich den Code posten. Aber ich möchte dazu sagen, dass ich hier im Anfänger-Forum poste, weil ich auch wirklich Anfänger bin ... aber okay, das hat man eh schon bemerkt.

Der Code ist sicherlich schlimm ...
Vielleicht liegt's einfach nur daran :(

Code:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;

public class HTTree {

    public static HTTree htt = new HTTree();
    public ArrayList<String> linkList = new ArrayList<String>();
    public ArrayList<ArrayList> adjList = new ArrayList<ArrayList>();
    public ArrayList<ArrayList> adjListNodeNames = new ArrayList<ArrayList>();
    public ArrayList<Integer> adjListIndex = new ArrayList<Integer>();
    public int listCnt = 0;
    public int nodeCnt = 0;
    public URL actUrl;
    public URL newUrl;
    public ArrayList<String> linksNotYetVisited = new ArrayList<String>();
    public int linksNotYetVisitedCnt = 0;
    public boolean isRoot = true;
    public static String path = "D:/Studies/";
    public int treeCnt = 0;
    public int[][] adjMatrix;
    public StringBuffer adjMatrixStr;

    public static void main(String[] args) throws Exception {
        htt.start();
    }

    public void start() {
        try {
            FileReader file = new FileReader(path + "data/links.txt");
            BufferedReader in = new BufferedReader(file);
            String line = null;
            int cnt = 1;

            while ((line = in.readLine()) != null) {

                linkList.clear();
                adjList.clear();
                adjListNodeNames.clear();
                adjListIndex.clear();
                listCnt = 0;
                nodeCnt = 0;
                linksNotYetVisited.clear();
                linksNotYetVisitedCnt = 0;

                actUrl = new URL(line);
                isRoot = true;
                getLinks(actUrl);
                int adjSize = adjList.size();

                if (adjSize > 1) {
                    adjMatrix = new int[adjSize][adjSize];
                    adjMatrixStr = new StringBuffer();

                    int i = 0;
                    int j = 0;
                    for (Iterator adlIterator = adjList.iterator(); adlIterator.hasNext();) {
                        ArrayList nl = (ArrayList) adlIterator.next();
                        for (Iterator nlIterator = nl.iterator(); nlIterator.hasNext();) {
                            j = (Integer) nlIterator.next();
                            adjMatrix[i][j] = 1;
                        }
                        i++;
                    }
                    writeMatrix(adjMatrix, "data/hypertexttrees/" + cnt + ".txt");
                    System.out.println("Hypertexttree Nr. " + cnt);
                }
                cnt++;
            }
            file.close();
        }
        catch (Exception e) {
            System.err.println(e);
            //e.getStackTrace();
        }
    }

    public void getLinks(URL url) {
        System.out.print(listCnt + ": " + url + "\n");
        ArrayList<String> nodeList = new ArrayList<String>();
        ArrayList<Integer> nodeListIndex = new ArrayList<Integer>();
        String link = "";
        Integer nodeIndex = -1;
        boolean isLinkWithinWebsite = false;
        boolean isInList = false;

        try {
            URLConnection con = url.openConnection();
            if (con.getContentType().contains("text/html")) { //Do only read file if it's of content-type text/html
                BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
                HTMLEditorKit editorKit = new HTMLEditorKit();
                HTMLDocument htmlDoc = new HTMLDocument();
                htmlDoc.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
                editorKit.read(br, htmlDoc, 0);
                HTMLDocument.Iterator iter = htmlDoc.getIterator(HTML.Tag.A);
                String actDomain = actUrl.toString(); //Actual Domain
                String actBase = "";
                String actPage;

                if (actDomain.endsWith("/")) {
                    actDomain = actDomain.substring(0, actDomain.length() - 1); //Cut off slash at end of URL if
                }
                //Add root node
                if (isRoot) {
                    nodeList.add(actDomain);
                    nodeListIndex.add(nodeCnt);
                    nodeCnt++;
                    isRoot = false;
                }

                //Iterate through all links of webpage
                while (iter.isValid()) {
                    link = String.valueOf(iter.getAttributes().getAttribute(HTML.Attribute.HREF));
                    if (link.contains("?")) {
                        link = link.substring(0, link.indexOf("?")); //Cut parameters off
                    }
                    if (link.contains("#")) {
                        link = link.substring(0, link.indexOf("#")); //Cut anchors off
                    }
                    //System.out.print(link);
                    //Absolute links
                    if (link.contains("http://")) {
                        if (link.contains(actDomain)) {
                            isLinkWithinWebsite = true;
                            //System.out.print(" -> " + link);
                        }
                    }
                    //Relative links (not implemented: relative links with base href)
                    else {
                        //Get actual page url
                        actPage = con.getURL().toString();
                        if ((actPage.lastIndexOf("/") < actPage.lastIndexOf(".") && (actPage.lastIndexOf("/") > 6))) {
                            actPage = actPage.substring(0, actPage.lastIndexOf("/"));
                        }
                        if (actPage.endsWith("/")) {
                            actPage = actPage.substring(0, actPage.length() - 1);
                        }
                        //Get base href if it exists
                        try {
                            actBase = htmlDoc.getBase().toString();
                            if (actBase.endsWith("/")) {
                                actBase = actBase.substring(0, actBase.length() - 1);
                            }
                            String tmpBase = actBase.substring(7, actBase.length());
                            if (tmpBase.contains("/")) {
                                tmpBase = tmpBase.substring(0, tmpBase.indexOf("/"));
                                actDomain = "http://" + tmpBase;
                            }
                        }
                        catch (Exception e) {
                            //System.err.println(e);
                        }
                        //Construate link
                        if ((!link.isEmpty()) && (!link.contentEquals("null")) && (!link.contains("://")) && (!link.contains("cript:")) && (!link.contains("mailto")) && (!link.contains("@"))) {
                            if (link.startsWith("/")) { //Link starts with "/"
                                link = link.substring(1, link.length());
                                link = actDomain + "/" + link;
                            }
                            else if (link.startsWith("../")) { //Link changes parent directory
                                while (link.contains("../")) {
                                    actPage = actPage.substring(0, actPage.lastIndexOf("/"));
                                    link = link.substring(3, link.length());
                                }
                                link = actPage + "/" + link;
                            }
                            else if (link.equals("./")) { //Link is a link at actual page
                                link = con.getURL().toString();
                            }
                            else if (link.startsWith("./")) { //Link remains in actual directory
                                while (link.contains("./")) {
                                    link = link.substring(2, link.length());
                                }
                                link = actPage + "/" + link;
                            }
                            else { //Normal relative link
                                if (link.startsWith("/")) {
                                    link = link.substring(1, link.length());
                                }
                                if (actBase.isEmpty()) {
                                    link = actPage + "/" + link;
                                }
                                else {
                                    link = actBase + "/" + link;
                                }
                            }
                            //System.out.print(" -> " + link);
                            isLinkWithinWebsite = true;
                        }
                    }
                    if (link.endsWith("/")) {
                        link = link.substring(0, link.length() - 1); //Strip slash at the end
                    }
                    //System.out.println("");

                    //If it's a link which has to be considered
                    if (isLinkWithinWebsite) {
                        //System.out.println(link);
                        isInList = false;
                        //Check if node is already in actual List
                        for (Iterator nlIterator = nodeList.iterator(); nlIterator.hasNext();) {
                            if (nlIterator.next().equals(link)) {
                                isInList = true;
                                break;
                            }
                        }
                        //Add new node to acutal node list
                        if (!isInList) {
                            //Check if link is already in adjacency list
                            nodeIndex = nodeAlreadyExists(link);
                            //Node is already in adjacency list and has it's own index, so use it
                            if (nodeIndex != -1) {
                                //System.out.println("link already known: " + nodeIndex + ", link: " + link);
                                nodeList.add(link);
                                nodeListIndex.add(nodeIndex);
                            }
                            //It is a new link
                            else {
                                //System.out.println("link is new: " + nodeIndex + ", link: " + link);
                                linksNotYetVisited.add(link);
                                nodeList.add(link);
                                nodeListIndex.add(nodeCnt);
                                nodeCnt++;
                            }
                        }
                    }
                    isLinkWithinWebsite = false;
                    iter.next();
                }
            }
        }
        //If site does not exist anymore
        catch (Exception e) {
            System.err.println(e);
            //e.printStackTrace();
        }
        //Add new node list to adjacency list
        adjList.add(nodeListIndex);
        adjListNodeNames.add(nodeList);
        adjListIndex.add(listCnt++);

        //Next url
        if (!(linksNotYetVisited.isEmpty())) {
            try {
                newUrl = new URL(linksNotYetVisited.get(0));
                linksNotYetVisited.remove(0);
                getLinks(newUrl);
            }
            catch (Exception e) {
                System.err.println(e);
            }
        }
    }

    //Check if node already exists and give back its index
    public int nodeAlreadyExists(String link) {
        int index = -1;
        int i = 0;
        int j = 0;
        for (Iterator adlIterator = adjListNodeNames.iterator(); adlIterator.hasNext();) {
            ArrayList nodeNameList = adjListNodeNames.get(i);
            ArrayList nodeIndexList = adjList.get(i);
            j = 0;
            for (Iterator nnlIterator = nodeNameList.iterator(); nnlIterator.hasNext();) {
                if (nodeNameList.get(j).equals(link)) {
                    index = (Integer) nodeIndexList.get(j);
                }
                nnlIterator.next();
                j++;
            }
            i++;
            adlIterator.next();
        }
        return index;
    }

    //Helper function to print childs of one node
    public void printAdjLine(ArrayList nodeList, ArrayList nodeListIndex) {
        int i = 0;
        for (Iterator nlIterator = nodeList.iterator(); nlIterator.hasNext();) {
            System.out.print("Node [" + nodeListIndex.get(i++) + "]: " + nlIterator.next() + "\n");
        }
    }

    //Helper function to print adjacency list
    public void printAdjList(ArrayList<ArrayList> adjList) {
        int i = 0;
        for (Iterator adlIterator = adjList.iterator(); adlIterator.hasNext();) {
            System.out.print("[" + i + "]: ");
            ArrayList nl = (ArrayList) adlIterator.next();
            for (Iterator nlIterator = nl.iterator(); nlIterator.hasNext();) {
                System.out.print(nlIterator.next() + ", ");
            }
            System.out.println();
            i++;
        }
    }

    //Writes the matrix string
    public void writeMatrix(int[][] matrix, String path) {
        for (int k = 0; k < matrix.length; k++) {
            for (int l = 0; l < matrix.length; l++) {
                //System.out.print(matrix[k][l] + " ");
                adjMatrixStr = adjMatrixStr.append(matrix[k][l]);
            }
            //System.out.println("");
            adjMatrixStr = adjMatrixStr.append("\r\n");
        }
        writeTextFile(String.valueOf(adjMatrixStr), path);
    }

    //Writes string into a textfile and saves it at given path
    public void writeTextFile(String string, String path) {
        try {
            BufferedWriter out = new BufferedWriter(new FileWriter(path));
            out.write(string);
            out.close();
        }
        catch (Exception e) {
            System.err.println("ERROR: " + e.getMessage());
        }
    }
}

:(
 
Zuletzt bearbeitet:

FArt

Top Contributor
Kurz den Code überflogen: du gibst immer nur Fehlermeldungen aus. Gib immer den kompletten Stacktrace aus. Du ruft immer wieder getLinks auf, schließt aber nie den Reader und den Stream. Vielleicht geht ja nicht der Speicher aus, sondern die Handles auf Systemressourcen.

[EDIT]
.. ist ja doch eine Rekursion. Sagtest du nicht, das wäre jetzt iterativ...? Wie groß ist denn deine Rekursionstiefe beim Fehler?
 
Zuletzt bearbeitet:

sunny01

Aktives Mitglied
Anfangs hatte ich auch immer den kompletten Stacktrace, beim Entwickeln ... der Fehler der lokal kommt ist aber trotzdem ein OutOfMemory ... kanns aber lokal nochmal laufen lassen mit gesamtem Stacktrace. Nur dauert das dann einige Stunden ... lokal läufts bei mir ja bis ca. 8.500 ... aber halt ewig langsam aufgrund meiner Internetverbindung.

Ja, ist immer noch ein rekursiver Aufruf drinnen, aber zumindest sollte jetzt alles sequentiell abgearbeitet werden ... also eine Unterseite komplett fertig auslesen, danach schauen ob es noch Links in der Liste gibt, wenn ja, wieder die Unterseite komplett fertig auslesen, danach schauen ob es noch immer Links in der Liste gibt ... etc.
Dachte ich zumindest.

Anfangs habe ich immer sofort bei einem neu entdeckten Link auf der Unterseite wieder die getLinks() aufgerufen ... sodass also in einem Funktionsaufruf durchaus noch viele weitere rekursive Aufrufe stattgefunden haben. Das habe ich nun zumindest nicht mehr, auch wenn sich die Funktion immer noch selbst aufruft. Aber eben erst am Ende ... und (so denke ich zumindest) sequentiell.
 

FArt

Top Contributor
Logge mal die Rekursionstiefe mit, gib die Fehler voll qualifiziert aus und schließe deinen Ressourcen, wenn du sie nicht mehr benötigst. Lass den Spaß dann noch mal laufen.
 

sunny01

Aktives Mitglied
Logge mal die Rekursionstiefe mit, gib die Fehler voll qualifiziert aus und schließe deinen Ressourcen, wenn du sie nicht mehr benötigst. Lass den Spaß dann noch mal laufen.

Die aktuelle Rekursionstiefe ist immer der aktuelle Knoten, in dem Fall ... also das was ich immer geschrieben habe mit "Knoten 5.000" ... dann war das der 5.000ste "rekursive" Aufruf.

Fehlerausgabe habe ich wieder angestellt ... am Server kommt dennoch nur "Segmentation fault" ohne Zusatzinformation.

Offen ist nur das eine Textfile, aus welchem ich die URLs meiner Webseiten auslese, welche ich auslesen soll. Ich kann versuchen es einfach gleich wieder zu schließen, nachdem ich die erste URL ausgelesen habe. Wie ich dann zur zweiten kommen würde, ist mir im Moment egal, da ich ja nichtmal die erste Website vollständig auslesen kann ... ich probier's also einfach mal.
 

homer65

Top Contributor
Ist das nicht schon ein Loop?
Code:
   public static HypertextTree htt = new HypertextTree();
Erscheint mir überdies sinnlos zu sein.
Lass doch mal diese Zeile weg und ersetze htt an allen anderen Stellen durch this.
 

sunny01

Aktives Mitglied
Lese jetzt zuerst das Textfile mit den URLs komplett ein (zum Testen steht da eh nur eine URL drinnen jetzt) und speichere die URLs auch in einer ArrayList ... sodass ich das File nicht mehr öffnen muss.
Ist ja im Moment nur genau 1 String, sollte also bezüglich Speicher nicht tragisch sein mit der weiteren Liste. Habs nochmal gestartet, sowohl lokal wie auch am Server. Inklusive StackTracePrint.

Das mit dem -Xloggc:datei habe ich im letzten Versuch gemacht, Inhalt der Datei:
1675.290: [GC 8388608K->31879K(32156352K), 0.1743900 secs]
 

sunny01

Aktives Mitglied
Ist das nicht schon ein Loop?
Code:
   public static HypertextTree htt = new HypertextTree();
Erscheint mir überdies sinnlos zu sein.
Lass doch mal diese Zeile weg und ersetze htt an allen anderen Stellen durch this.

Ein Loop? Wieso das denn?
Kommt eigentlich ohnehin nur bei htt.start() vor ...
die getLinks() kann ich auch so aufrufen. Versteh' ich jetzt grad nicht wieso das ein Loop ist. ???:L
Aber okay ich änder das mal für den nächsten Durchlauf ...

EDIT:

Code:
public static void main(String[] args) throws Exception {
        this.start();
}

Das kann aber nicht funktionieren ... "non-static variable this cannot be referenced from a static context".
 
Zuletzt bearbeitet:

sunny01

Aktives Mitglied
Wo denn? Ich seh das nicht. Das ist doch komplett außerhalb des Loops ... es passiert doch alles in der getLinks, und dort wird kein Hypertexttree mehr erstellt. ???:L
 

faetzminator

Gesperrter Benutzer
Nochmals, für die JConsole:
- Installier XMing und Putty (natürlich kannst statt Putty du auch irgendwie deinen bisherigen SSH Client so einrichten)
- Starte XMing
- Starte Putty
- Stelle in Putty X11 Forward ein (Connection -> SSH -> X11)
- Verbinde
- Starte jconsole
- Freu dich

Als Alternative:
Lass JConsole auf deinem Rechner lokal laufen und verbinde zum Server, wär wohl einfacher (für den *nix Laien) ;)
 
M

maki

Gast
Er hat nur das JRE installiert und benötigt auch nur das JRE ;)
Aber man siehe...
Code:
[faetzminator@fkaros ~]$ apt-cache search sun-java6
sun-java6-source - Sun Java(TM) Development Kit (JDK) 6 source files
sun-java6-jre - Sun Java(TM) Runtime Environment (JRE) 6 (architecture independent files)
sun-java6-javadb - Java(TM) DB, Sun Microsystems' distribution of Apache Derby
sun-java6-fonts - Lucida TrueType fonts (from the Sun JRE)
sun-java6-plugin - The Java(TM) Plug-in, Java SE 6
sun-java6-jdk - Sun Java(TM) Development Kit (JDK) 6
sun-java6-demo - Sun Java(TM) Development Kit (JDK) 6 demos and examples
sun-java6-bin - Sun Java(TM) Runtime Environment (JRE) 6 (architecture dependent files)
ia32-sun-java6-bin - Sun Java(TM) Runtime Environment (JRE) 6 (32-bit)
IME bekommt man dann immer das OpenJDK, aber davon abgesehen hat er wohl doch ein JDK installiert (siehe den Server Hotspot JIT).
 

FArt

Top Contributor
Nochmals, für die JConsole:
- Installier XMing und Putty (natürlich kannst statt Putty du auch irgendwie deinen bisherigen SSH Client so einrichten)
- Starte XMing
- Starte Putty
- Stelle in Putty X11 Forward ein (Connection -> SSH -> X11)
- Verbinde
- Starte jconsole
- Freu dich

Als Alternative:
Lass JConsole auf deinem Rechner lokal laufen und verbinde zum Server, wär wohl einfacher (für den *nix Laien) ;)

Das klappt aber nur, wenn auf dem Server X11 überhaupt installiert ist... ist oft nicht der Fall.
 

sunny01

Aktives Mitglied
Also das offene Textfile war's nicht ... genau derselbe Effekt ohne Textfile am Server ... bei etwa Knoten 5.000 kommt Segmentation fault. Es kommt auch trotz Ausgabe des gesamten Stacks der Exception nicht mehr Info. Aber das habe ich ja schon vermutet.

Ich werde mir nun das mit dem XMing ansehen.
 

sunny01

Aktives Mitglied
Also es kommt dann ein Fenster, da steht "JConsole: New Connection".
Ich habe dort "Remote Process:" angeklickt und dann den Hostnamen des Servers eingetragen sowie :9090 für den Port. Stimmt das nicht? Es kommt dann nämlich "Connection refused". Muss ich da mit dem Port irgendetwas anders machen oder vorher einstellen?

Username und Passwort habe ich natürlich auch eingegeben.

EDIT: Achso, das ist wahrscheinlich eh der Local Process ... wenn ich das doch schon über putty starte ... sorry
 

Ähnliche Java Themen

Neue Themen


Oben