# "Segmentation fault" Virtual Machine Konfiguration Großrechner?



## sunny01 (17. Jun 2010)

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 (17. Jun 2010)

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.


----------



## homer65 (17. Jun 2010)

Offensichtlich hatt der Rechner mehr als 4GB RAM. Vielleicht gibt es da ein Durcheinander von 32 Bit und 64 Bit Packeten?


----------



## sunny01 (17. Jun 2010)

Guten Morgen!



FArt hat gesagt.:


> 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: 



FArt hat gesagt.:


> 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. 



FArt hat gesagt.:


> Bricht die VM ab, wenn der Fehler kommt?


Ja leider ... das ist ja das Problem. 



FArt hat gesagt.:


> Gibt es dann einen Dump?


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



FArt hat gesagt.:


> 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). 



FArt hat gesagt.:


> Benutzt die Applikation native Komponenten (JNI oder Datenbanktreiber)?


Eigentlich nicht. An externen Libraries sind in Verwendung: JDom und HTMLCleaner. 



FArt hat gesagt.:


> 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


----------



## homer65 (17. Jun 2010)

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 (17. Jun 2010)

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 (17. Jun 2010)

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).


----------



## homer65 (17. Jun 2010)

sunny01 hat gesagt.:


> 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.


----------



## homer65 (17. Jun 2010)

Hab mal geguckt:
Java-Downloads für alle Betriebssysteme - Sun Microsystems
Dort nach Linux suchen.
Dann Linux x64 auswählen.


----------



## sunny01 (17. Jun 2010)

FArt hat gesagt.:


> 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. 



FArt hat gesagt.:


> 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? 



FArt hat gesagt.:


> 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?



FArt hat gesagt.:


> 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 (17. Jun 2010)

homer65 hat gesagt.:


> 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 ... 



homer65 hat gesagt.:


> 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


----------



## homer65 (17. Jun 2010)

sunny01 hat gesagt.:


> Zum auf dem Server installieren? Kann ich das selber machen? Wohl kaum, oder doch?
> Lg
> sunny



Warum nicht. Versuch macht klug.


----------



## Guest2 (17. Jun 2010)

Moin,



sunny01 hat gesagt.:


> ~$ 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 (17. Jun 2010)

> 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


----------



## sunny01 (17. Jun 2010)

Mit den Parameterwerten von homer65 kam nun wieder die OutOfMemoryException 



> Exception in thread "main" java.lang.OutOfMemoryError: Java heap space



Werde noch die Werte von Fancy probieren.


----------



## homer65 (17. Jun 2010)

Guest2 hat gesagt.:


> er nutzt doch eine 64Bit VM.


Ups, hab ich übersehen, sorry.


----------



## sunny01 (17. Jun 2010)

Ich hab das JAR aber unter Windows 32bit erstellt ... kann das das Problem sein!?


----------



## homer65 (17. Jun 2010)

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.


----------



## faetzminator (17. Jun 2010)

Unter Linux wird (normalerweise...) *nie* ein Programm von Hand installiert, dafür gibt's da einen Paketmanager (apt). Wenn da was nicht stimmt, sprich mit dem Sysadmin.


----------



## maki (17. Jun 2010)

faetzminator hat gesagt.:


> Unter Linux wird (normalerweise...) *nie* ein Programm von Hand installiert, dafür gibt's da einen Paketmanager (apt). Wenn da was nicht stimmt, sprich mit dem Sysadmin.


Das Original SUN JDK muss man von Hand installieren


----------



## sunny01 (17. Jun 2010)

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 (17. Jun 2010)

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 (17. Jun 2010)

maki hat gesagt.:


> 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...

```
[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 (17. Jun 2010)

FArt hat gesagt.:


> 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*



FArt hat gesagt.:


> 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 ... ;(


----------



## homer65 (17. Jun 2010)

Also: –Xmx32768m –Xms32768m als Option und dann mit JMX beobachten. Mach mal.


----------



## sunny01 (17. Jun 2010)

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)
> ...



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


----------



## faetzminator (17. Jun 2010)

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 (17. Jun 2010)

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 (17. Jun 2010)

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


----------



## homer65 (17. Jun 2010)

Da fällt mir noch ein, das wenn du kein PC Linux hast, kannst du XMing unter Windows benutzen:
Xming X Server for Windows | Download Xming X Server for Windows software for free at SourceForge.net


----------



## Guest2 (17. Jun 2010)

sunny01 hat gesagt.:


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



Jetzt werd ich neugierig. 

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 (17. Jun 2010)

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 (17. Jun 2010)

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 


```
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());
        }
    }
}
```


----------



## FArt (17. Jun 2010)

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?


----------



## sunny01 (17. Jun 2010)

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 (17. Jun 2010)

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 (17. Jun 2010)

Guest2 hat gesagt.:


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



Ist nicht vorhanden.


----------



## sunny01 (17. Jun 2010)

> 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 (17. Jun 2010)

Ist das nicht schon ein Loop?

```
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 (17. Jun 2010)

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 (17. Jun 2010)

homer65 hat gesagt.:


> Ist das nicht schon ein Loop?
> 
> ```
> public static HypertextTree htt = new HypertextTree();
> ...



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: 


```
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".


----------



## homer65 (17. Jun 2010)

Na du machst im HypertextTree einen neuen HypertextTree auf, der einen HypertextTree aufmacht und so weiter ad Inifitum.


----------



## sunny01 (17. Jun 2010)

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


----------



## FArt (17. Jun 2010)

homer65 hat gesagt.:


> Na du machst im HypertextTree einen neuen HypertextTree auf, der einen HypertextTree aufmacht und so weiter ad Inifitum.



Ne, ist doch statisch...


----------



## faetzminator (17. Jun 2010)

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)


----------



## maki (17. Jun 2010)

faetzminator hat gesagt.:


> Er hat nur das JRE installiert und benötigt auch nur das JRE
> Aber man siehe...
> 
> ```
> ...


IME bekommt man dann immer das OpenJDK, aber davon abgesehen hat er wohl doch ein JDK installiert (siehe den Server Hotspot JIT).


----------



## FArt (17. Jun 2010)

faetzminator hat gesagt.:


> 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
> ...



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


----------



## sunny01 (17. Jun 2010)

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.


----------



## faetzminator (17. Jun 2010)

FArt hat gesagt.:


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



Wirklich? Ich kenn zwar Server ohne DE's, aber ganz ohne X11? Naja, we'll see


----------



## sunny01 (17. Jun 2010)

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


----------



## sunny01 (17. Jun 2010)

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


----------



## maki (17. Jun 2010)

Was passiert, wenn du den Stack selber konfigurierst (zB. -Xss=8m)?

Kannst du vielleciht ein anderes, u.U. älteres JDK (parallel) installieren und damit nochmals testen?


----------



## sunny01 (17. Jun 2010)

maki hat gesagt.:


> Was passiert, wenn du den Stack selber konfigurierst (zB. -Xss=8m)?




```
Invalid thread stack size: -Xss=8m
Could not create the Java virtual machine.
```



maki hat gesagt.:


> Kannst du vielleciht ein anderes, u.U. älteres JDK (parallel) installieren und damit nochmals testen?



Wenn ich wüsste wie das funktioniert ...


----------



## sunny01 (17. Jun 2010)

Also diese JConsole ist extrem langsam ... ist das normal? Wenn ich irgendeinen Reiter anklicke dauert das seeehr lang, bis irgendetwas passiert. 
Und, wie kann ich, wenn ich die JConsole gestartet habe, dann noch mein JAR-File starten? Die Eingabeaufforderung kommt dann in der Konsole (von putty) nicht.


----------



## faetzminator (17. Jun 2010)

sunny01 hat gesagt.:
			
		

> Ich habe dort "Remote Process:" angeklickt und dann den Hostnamen des Servers eingetragen sowie :9090 für den Port. Stimmt das nicht?


Du solltest nach [c]localhost[/c] bzw. [c]127.0.0.1[/c] verbinden können. Allerdings muss dein Programm bzw. die JVM dann natürlich laufen.



sunny01 hat gesagt.:


> Und, wie kann ich, wenn ich die JConsole gestartet habe, dann noch mein JAR-File starten? Die Eingabeaufforderung kommt dann in der Konsole (von putty) nicht.



- mit [c]jconsole &[/c] den Prozess im Hintergrund starten
- oder zweites Putty öffnen
- oder [c]screen[/c] verwenden
- oder ...


----------



## sunny01 (17. Jun 2010)

faetzminator hat gesagt.:


> Du solltest nach [c]localhost[/c] bzw. [c]127.0.0.1[/c] verbinden können. Allerdings muss dein Programm bzw. die JVM dann natürlich laufen.



Ja, sorry, hatte da falsch herum gedacht ... hatte den Beitrag dann noch editiert. 



faetzminator hat gesagt.:


> - mit [c]jconsole &[/c] den Prozess im Hintergrund starten
> - oder zweites Putty öffnen
> - oder [c]screen[/c] verwenden
> - oder ...



Super, danke! Hat funktioniert ... jetzt läuft JConsole und mein Programm. 
Was soll ich jetzt am Besten beobachten? Die JConsole ist wirklich gaaaanz langsam ... da tut sich Sekunden bis Minuten gar nichts ...


----------



## sunny01 (17. Jun 2010)

Also falls das was bringt ... so sieht die JConsole nach dem "Segmentation fault" aus: 







Lokal, wo dieser Fehler ja nie kam, sondern immer ein OutOfMemory läuft das Script noch ... wie gesagt, es ist bedeutend langsamer aufgrund der schwächeren Internetverbindung ... aber komischerweise kommt das Programm lokal "weiter" als auf dem Server, bis ein Fehler kommt ...


----------



## homer65 (17. Jun 2010)

Nach zuviel Memory Verbrauch sieht es also nicht aus. Das können wir jetzt ausschließen.
Dann bleibt nur noch ein richtiger Bug.
Bleibt also nur auf die neueste Version von Sun Java hochrüsten.
Und wenn der Fehler weiterhin kommt:
Bug Database


----------



## sunny01 (17. Jun 2010)

Und an meinem stümperhaften Quelltext kann der Fehler auch nicht liegen? 
Wegen einem Java-Update müsste ich wohl wieder mit dem Zuständigen für den Server sprechen ... 

Es ist alles so komisch, zumal das Ganze bei mir am Rechner ja sogar länger bzw. tiefer läuft als auf dem Server ... dass bei mir am Rechner irgendwann der Speicher aus ist, kann ich mir schon vorstellen ... Aber auf dem Großrechner eben irgendwie auch nicht ... 

Es scheint wohl aussichtslos ...


----------



## homer65 (17. Jun 2010)

Kopf hoch, aussichtslos ist es nicht.
Aber für solche Probleme gibt es in normalen Firmen eben Sysprogs, die sich drum kümmern.
Man muß nur mal mit den Leuten reden.


----------



## sunny01 (17. Jun 2010)

Okay, dann versuche ich es nochmal ... der Kerl hat mich gestern schon "zur Sau" gemacht ... und ich bekomme immer nur Antworten wie "das geht sowieso nicht, lass es lokal laufen".


----------



## faetzminator (17. Jun 2010)

Für das kann man über die Linie eskalieren, auch wenns unschön ist...


----------



## FArt (17. Jun 2010)

Auffallend: die mittlere Säule vom Heap ist auf 100%... das ist der Survivor Space. Kann aber auch Zufall sein.

Normalerweise sollte jetzt eine GC einsetzten und die Objekte in die Tenured Generation verschieben.

Versuche mal ein wenig Tuning bzgl. GC Algorithmen (z.B. parallele GC, siehe Java HotSpot VM Options 

Noch ein paar Tipps in der Richtung:
Java Tuning White Paper

Zeige doch mal den Verlauf der einzelnen Heap-Spaces.


----------



## homer65 (17. Jun 2010)

Ein Punkt (ist natürlich nur eine Idee mehr nicht) der mich stört ist:

```
public static HypertextTree htt = new HypertextTree();
```
Kannst du nicht deinen Code in eine zweite Klasse auslagern und nur die main Methode in der ersten Klasse belassen, so das du dieses unschöne (mir fehlen die passenden Worte) Konstrukt los wirst.
Aber wie gesagt, das ist ins Blaue geraten.


----------



## sunny01 (17. Jun 2010)

FArt hat gesagt.:


> Auffallend: die mittlere Säule vom Heap ist auf 100%... das ist der Survivor Space. Kann aber auch Zufall sein.



Das ist aber immer so. Selbst wenn ich mein Programm noch gar nicht gestartet habe. 



FArt hat gesagt.:


> Versuche mal ein wenig Tuning bzgl. GC Algorithmen (z.B. parallele GC, siehe Java HotSpot VM Options
> 
> Noch ein paar Tipps in der Richtung:
> Java Tuning White Paper



Oh mann ... 



FArt hat gesagt.:


> Zeige doch mal den Verlauf der einzelnen Heap-Spaces.



Wie mache ich das? Wenn ich auf das Dropdown von "Chart" klicke, muss ich erstmal über eine Minute warten, bis sich überhaupt die Auswahlliste öffnet. Aber falls es das ist, was Du meinst, hier die verschiedenen Heaps-Spaces auszuwählen, dann werde ich das jetzt mal versuchen.


----------



## FArt (17. Jun 2010)

Du kannst auf eine der Säulen klicken... also die mittlere...

Dass das bei dir immer so ist, ist auf jeden Fall ungewöhnlich... aber ob das ein Problem ist ???


----------



## sunny01 (17. Jun 2010)

homer65 hat gesagt.:


> Ein Punkt (ist natürlich nur eine Idee mehr nicht) der mich stört ist:
> 
> ```
> public static HypertextTree htt = new HypertextTree();
> ...



Jetzt sieht es so aus: 


```
public class HTT {
    public static void main(String[] args) {
        HTAdjMatrix htam = new HTAdjMatrix();
        htam.start();
    }
}
```

Und in HTAdjMatrix ist der gesamte Rest. 

Habs nochmal am Server gestartet.


----------



## Guest2 (17. Jun 2010)

Nur für den Fall das das untergegangen ist, FArt sprach es schon an:

br.close();

Gruß,
Fancy


----------



## sunny01 (17. Jun 2010)

FArt hat gesagt.:


> Du kannst auf eine der Säulen klicken... also die mittlere...
> 
> Dass das bei dir immer so ist, ist auf jeden Fall ungewöhnlich... aber ob das ein Problem ist ???








Warum das immer so ist, weiß ich auch nicht. Kann es passieren, dass so ein Programm noch weiterläuft, irgendwie, irgendwo!? Also nach dem Segmentation fault? Aber es kommt dann dann einfach wieder das Eingabezeichen der Konsole. Dann müsste es doch beendet sein, das Programm.


----------



## faetzminator (17. Jun 2010)

Mit [c]ps[/c] kannst du auf der Konsole die laufenden Prozesse ausgeben. Sieh dir dazu [c]ps -?[/c] oder [c]man ps[/c] an. Allerdings denke ich, dass da kein Prozess mehr läuft.


----------



## sunny01 (17. Jun 2010)

> br.close();



Stimmt ... und ich habe nur auf die Datei zum Auslesen der Linkliste geachtet,  nicht auf den BufferedReader, der den Sourcecode der Webseiten einliest. Hab' das jetzt geändert ... und nochmal gestartet. 



> Mit ps kannst du auf der Konsole die laufenden Prozesse ausgeben. Sieh dir dazu ps -? oder man ps an. Allerdings denke ich, dass da kein Prozess mehr läuft.



Nein, läuft nur der eine ...


----------



## fastjack (17. Jun 2010)

Stell doch mal lokal bei dir dieselbe Situation dar und probiere das Programm dann auf dem lokalen Rechner (mit echten Daten, Dateien die Du vorher kopiert hast) nach.


----------



## sunny01 (17. Jun 2010)

sunny01 hat gesagt.:


> Warum das immer so ist, weiß ich auch nicht. Kann es passieren, dass so ein Programm noch weiterläuft, irgendwie, irgendwo!? Also nach dem Segmentation fault? Aber es kommt dann dann einfach wieder das Eingabezeichen der Konsole. Dann müsste es doch beendet sein, das Programm.



Interessanterweise ist es auf dem Screenshot, den ich gepostet habe, ja gar nicht so. Also doch nicht immer so. Ich bin schon ganz durcheinander. Mir war nur einmal aufgefallen, dass schon beim Öffnen der JConsole, noch bevor ich mein Programm gestartet hab, der mittlere Balken auf fast 100 % war ... aber vielleicht bin ich jetzt auch schon völlig verrückt.


----------



## sunny01 (17. Jun 2010)

fastjack hat gesagt.:


> Stell doch mal lokal bei dir dieselbe Situation dar und probiere das Programm dann auf dem lokalen Rechner (mit echten Daten, Dateien die Du vorher kopiert hast) nach.



Das habe ich heute schon gemacht. Habe auch gepostet, dass ich das Programm lokal nochmal starte (mit denselben Gegebenheiten wie am Server). Ich habe dann wieder bei ~ Knoten 10.000 manuell abgebrochen, weil es lokal einfach langsam läuft und ewig lang dauert ... Fehler kommt aber keiner.


----------



## fastjack (17. Jun 2010)

Lokal ausprobieren, mit denselben Daten.

Wir hatten öfters Schwierigkeiten bei 64bit Rechnern, FreeBSD und verschiedenen 64bit JDK/JRE.


----------



## sunny01 (17. Jun 2010)

Ich hab doch schon mehrmals gesagt dass es lokal läuft ... aber so langsam, dass es mir nichts bringt, weil eine Website fast einen ganzen Tag braucht bzw. nach einem ganzen Tag immer noch fertig durchgearbeitet ist, ich muss aber 500 auslesen, und das bis nächste Woche. Daher habe ich jedes Mal bei etwa 10.000 ausgelesenen Seiten abgebrochen ... das waren dann meist schon um die 8 h ... so komme ich nicht weiter. 

Meine Internetverbindung lokal ist einfach zu langsam, es wird ja auf jede Unterseite eine URLConnection erstellt, um von dort wieder die Links auslesen zu können. Lokal dauert das, aufsummiert, leider ewig. Dass es lokal funktioniert hilft mir also absolut nicht weiter. 



PS: Anfangs hatte ich allerdings lokal auch Speicherprobleme ... ich muss beim Starten auch die VM-Parameter mitgeben, damit es bis 10.000 Knoten läuft ...


----------



## fastjack (17. Jun 2010)

> weil es lokal einfach langsam läuft



Naja, dann würde ich erstmal lokal die ganze Sache auf einen Stand bringen, der nicht quälend langsam läuft. Also Programmierfehler/bugs raus und ein wenig den Algorithmus optimieren, vielleicht Schleifendurchläufe sparen etc.


----------



## fastjack (17. Jun 2010)

Ok, zu spät geschrieben. Was soll denn überhaupt mit den Websites gemacht werden?


----------



## sunny01 (17. Jun 2010)

Bin leider nicht so gut in Java. 
Sehe aber den größten Flaschenhals an der Internetverbindung ... das ist einfach das, was Zeit benötigt. Ich habe hier nur Wireless ... der Server hat eine weiß-ich-wieviele-MBit-Standleitung. 

Die Schleifendurchläufe werden wahrscheinlich am Server auch schneller sein, das ist klar ... aber ohne Schleife wüsste ich nicht, wie ich das programmieren soll. Auch habe ich nicht mehr viel Zeit, alles neu zu programmieren, selbst wenn ich eine Idee hätte, wie man es besser machen kann. Das kann man nämlich mit Sicherheit, ich habe nicht viel Erfahrung mit Java.


----------



## FArt (17. Jun 2010)

Speichermenge schein also nicht das Problem zu sein...


----------



## sunny01 (17. Jun 2010)

Ich habs ganz vorne schonmal geschrieben ... es soll pro Website ein Graph erstellt werden, der die interne Verlinkung wiedergibt. Den Graphen repräsentiere ich einfach als Adjazenzmatrix. 

Damit ich aber diese erstellen kann, muss ich immer wissen, welche Links ich schon "kenne", und welche neu sind. Wenn ich den Link schon "kenne", dann muss ich auch seine ID herausfinden, damit ich ihn mit dem aktuellen Knoten "verknüpfen" kann. 

Es soll dann eben ein gerichteter Graph hehrauskommen, in dem die Knoten alle Unterseiten einer Website sind, und die Kanten die jweiligen Verbindungen zwischen ihnen, also die Hyperlinks.

Ich speichere zuerst alles in Adjazenzlisten, und generiere dann am Schluss aus der Adjazenzliste die Adjazenzmatrix. Die Adjazenzliste muss eben während des Durchsuchens einer Website im Speicher gehalten werden (DBs sollen nicht verwendet werden) ... kann mir nicht vorstellen, wie das sonst funktionieren soll ...


----------



## fastjack (17. Jun 2010)

Ok, auch wenns schonmal gesgat wurde. Bei solchen Vorhaben sollte man eine maximale Rekursionstiefe angeben, da man ansonsten ganz schnell mal das Internet herunterlädt  
Ich habe dein Programm mal auf die Google-Eingabeseite laufen lassen und er hat schon über 300 Links gefunden (ohne die Suche aktiviert zu haben)...


----------



## sunny01 (17. Jun 2010)

Was hast Du denn da für links gefunden? 

Ich lasse mir die Links zur Zeit immer alle mitausgeben, die besucht werden, und sie befinden sich immer in derselben Domain und sind auch die, die wirklich verfolgt werden sollen. Außerhalb der Domain darf nichts abgegrast werden, sonst hab ich am Ende wirklich das ganze Internet geladen ...


----------



## fastjack (17. Jun 2010)

425: http://www.google.de/intl/de/mobile/navigation/search-along-route.jpg
426: http://www.google.de/intl/de/mobile/navigation/satellite-view.jpg
427: http://www.google.de/intl/de/mobile/navigation/car-dock.jpg
428: http://www.google.de/intl/de/mobile/navigation/shortcut.jpg
429: http://www.google.de/intl/de/mobile/google-mobile-app/gma-iphone-search-by-voice-working.jpg
430: http://www.google.de/intl/de/mobile/google-mobile-app/mylocation.jpg
431: http://www.google.de/intl/de/mobile/google-mobile-app/googlesuggest.jpg
432: http://www.google.de/intl/de/mobile/google-mobile-app/searchhistory.jpg
433: http://www.google.de/intl/de/mobile/google-mobile-app/emailsearch.jpg
434: http://www.google.de/intl/de/mobile/google-mobile-app/contactsearch.jpg
435: http://www.google.de/intl/de/mobile/google-mobile-app/verticalsearch.jpg
436: http://www.google.de/intl/de/mobile/google-mobile-app/links.jpg
437: Google Mobile
438: Ihren Content bermitteln
439: Google-Pressezentrum
440: Google-Pressezentrum
441: Google-Pressezentrum
442: Pressezentrum - FIFA.com und Google unterstützen Fans beim Feiern der Fußball-WM 2010
443: Pressezentrum - Guggenheim-Museum und YouTube suchen das weltweit kreativste Online-Video
444: Pressezentrum - Statement zu der Kritik der Datenschutzbeauftragten, dass Google Wi-Fi-Daten erfasst
445: Life at Google - Germany jobs - Google
446: Explore our offices - Germany jobs - Google
447: Joining Google - Germany jobs - Google
448: Düsseldorf Advertising Sales & Customer Support - Germany jobs - Google
449: Frankfurt Advertising Sales & Customer Support - Germany jobs - Google
450: Hamburg Advertising Sales & Customer Support - Germany jobs - Google

in links.txt ist ein Eintrag Google


----------



## sunny01 (17. Jun 2010)

Also ich habs grad mit meinem aktuellen Script (lokal) probiert mit Google und es bleibt bei mir alles schön auf Google ... keine Fremddomains ...


----------



## sunny01 (17. Jun 2010)

Aber die sind doch alle richtig ...


----------



## fastjack (17. Jun 2010)

Das hatte sich nicht auf Fremddomäns bezogen, sondern auf die Langsamheit. Der Algo hat ordentlich zu rödeln, das meinte ich


----------



## sunny01 (17. Jun 2010)

Ja das ist mir auch schon aufgefallen ... 

Das ist doch mein eigentliches Problem weshalb ich hier bin ... auf dem Server läuft ja alles nur bis ungefähr 6.000 Unterseiten und ich weiß nicht warum ... und auf meinem Computer zu Hause dauert es zu lange.


----------



## FArt (17. Jun 2010)

```
public class TestMe  {

  public static int MAX = 10000;

  public void testMe() throws Exception {
    testMe(1);
  }

  private void testMe(int i) throws Exception {
    if (i == MAX)
      return;
    {
      URL url = new URL("http://www.google.de");
      URLConnection con = url.openConnection();
      BufferedReader br = new MyBufferedReader(new InputStreamReader(con.getInputStream()));
      System.out.println(i);
//      br.close();
//      br = null;
    }
    testMe(i + 1);
  }

  private static class MyBufferedReader extends BufferedReader {

    MyBufferedReader(InputStreamReader isr) {
      super(isr);
    }

    public void finalize() throws Throwable {
      super.finalize();
      System.out.println("********** Collected Reader ***********");
    }

  }

  public static void main(String[] args) throws Exception {
    new TestMe().testMe();
  }

}
```

Das gibt einen OutOfMemory. Der Reader wird wohl nicht collected. Mit close() und nullen schon...

Und baue die Rekursion aus...


----------



## fastjack (17. Jun 2010)

Bei Passagen, in denen du nach einem Element suchst, ob es schon vorhanden ist, iterierst Du durch eine immer größer werdende Liste. Das kostet Zeit, da hilft unter Umständen eine Map, in der Du die Einträge speichert und einfach mit contains() prüfst, ob es ein Element gibt dazu gibt.
Ich schau mal, ob ich noch mehr finde ...


----------



## sunny01 (17. Jun 2010)

Aber das mit dem fehlenden close() vom BufferedReader habe ich ja schon behoben. Oder was meinst Du genau. 

Das mit der Map habe ich mir auch schon gedacht, allerdings glaube ich nicht, dass es daran liegt, dass am Server die Iteration zu viel wird ... weil es ja sogar bei mir lokal am Rechner länger läuft als am Großrechner. Der Aufwand das Suchen des Knotens umzuprogrammieren wird nicht lohnen, weil der Segmentation fault bestimmt trotzdem kommt.


----------



## fastjack (17. Jun 2010)

> weil der Segmentation fault bestimmt trotzdem kommt.



ja, der kommt dann aber früher  Und Dein Proggi wird vielleicht bald keinen Großrechner mehr brauchen.


----------



## sunny01 (17. Jun 2010)

Und dann programmiere ich da jetzt ewig lange herum (Maps habe ich noch nie implementiert, kenne ich mich überhaupt nicht damit aus) und danach funktioniert es auch nicht viel schneller, weil es einfach an meiner Internetverbindung liegt, und dann habe ich auch keine Zeit mehr, den Fehler am Server zu finden. Auch mit Maps wird das Programm nicht in einem Tag 500 große Websiten durcharbeiten können. Da bin ich sicher. 
Am Wochenende ist dann auch niemand da, der irgendwas am Server umstellen könnte, falls das was helfen würde. Dann habe ich komplett verloren wenn es morgen nicht auf meinem lokalen Rechner so schnell läuft, dass übers WE alle 500 Seiten heruntergeladen sind. Das ist doch unmöglich. 

Ich weiß nicht mehr weiter. Langsam denke ich schon fast ans Aufgeben.


----------



## FArt (17. Jun 2010)

sunny01 hat gesagt.:


> Aber das mit dem fehlenden close() vom BufferedReader habe ich ja schon behoben. Oder was meinst Du genau.
> 
> Das mit der Map habe ich mir auch schon gedacht, allerdings glaube ich nicht, dass es daran liegt, dass am Server die Iteration zu viel wird ... weil es ja sogar bei mir lokal am Rechner länger läuft als am Großrechner. Der Aufwand das Suchen des Knotens umzuprogrammieren wird nicht lohnen, weil der Segmentation fault bestimmt trotzdem kommt.
> 
> Wie soll ich die Rekursion komplett rausbringen? Das wird dann extrem umständlich mit noch mehr Iterationen, kann ich mir grad nicht richtig vorstellen.



Ich muss mir mal in einer ruhigen Minute darüber Gedanken machen was da genau schief läuft.

Probier das Testprogramm ruhig aus. Nur der close() reicht noch nicht, du musst die Referenz auch auf null setzen, damit der GC den Reader rechtzeitig abräumt.


----------



## sunny01 (17. Jun 2010)

Achso, okay, ich schau mir das mit dem null-Setzen an ... das habe ich tatsächlich nicht gemacht.


----------



## fastjack (17. Jun 2010)

Das stimmt natürlich, daß bezog sich auch nur auf die eigentliche Verarbeitungsgeschwindigkeit. Der größte Zeitfresser ist aber sowieso das Lesen aus der Verbindung. Hast Du die Exception mal alle eingeblendet, also die e.printStackTraces() überall ? Kannst Du sie posten ?


----------



## FArt (17. Jun 2010)

Stimmt nicht. Das Testprogramm entpsricht nicht deinem Programm. Der Scope für den Reader ist hier falsch gewählt. In deinem Fall müsste er collected werden. Jetzt passt auch meine Theorie wieder.. und dein Problem ist noch da.

Baue die Rekursion aus ;-)


----------



## fastjack (17. Jun 2010)

Mir ist noch eingefallen, wir hatten auf einer SPARC-Maschine mit 16GIG, FreeBsd und 64bit Diablo Java, ein ähnliches Problem. Schuld daran war ein defekter Speicherriegel. Wir haben bei jedem Programmstart ein Stück defekten Speicher bekommen, bei erschiedensten Memore-Einstellungen. Sysop hat die Riegel nacheinander einzeln und wieder eingesteckt, bis es lief und er den defekten hatte.


----------



## sunny01 (17. Jun 2010)

fastjack hat gesagt.:


> Das stimmt natürlich, daß bezog sich auch nur auf die eigentliche Verarbeitungsgeschwindigkeit. Der größte Zeitfresser ist aber sowieso das Lesen aus der Verbindung. Hast Du die Exception mal alle eingeblendet, also die e.printStackTraces() überall ? Kannst Du sie posten ?



Exceptions treten eigentlich nur bei toten Links auf und sehen dann folgendermaßen aus: 


```
java.io.FileNotFoundException: http://www.xxx.com/yyy/zzz.html
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:1368)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.net.www.protocol.http.HttpURLConnection.getChainedException(HttpURLConnection.java:1362)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1016)
```


----------



## FArt (17. Jun 2010)

Nachtrag:
so passt der Scope des Readers.. und der GC macht alles gut...

```
private void testMe(int i) throws Exception {
    if (i == MAX)
      return;
    if (i < MAX){ // logisch unnötig, aber der Scope des Readers ist wichtig...
      URL url = new URL("http://localhost:8080");
      URLConnection con = url.openConnection();
      BufferedReader br = new MyBufferedReader(new InputStreamReader(con.getInputStream()));
      System.out.println(i);
    }
    testMe(i + 1);
  }
```


----------



## sunny01 (17. Jun 2010)

> Mir ist noch eingefallen, wir hatten auf einer SPARC-Maschine mit 16GIG, FreeBsd und 64bit Diablo Java, ein ähnliches Problem. Schuld daran war ein defekter Speicherriegel. Wir haben bei jedem Programmstart ein Stück defekten Speicher bekommen, bei erschiedensten Memore-Einstellungen. Sysop hat die Riegel nacheinander einzeln und wieder eingesteckt, bis es lief und er den defekten hatte.



Aber wenn es an kaputtem Speicher läge, dann würde doch nicht immer zum ungefähr selben Zeitpunkt im Ablauf des Programms der Fehler kommen ... oder?


----------



## sunny01 (17. Jun 2010)

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


----------



## fastjack (17. Jun 2010)

Ich weis jetzt nicht, ob es eine konstante Zeit war, aber es hat schon etwas gedauert, bis der Fehler kam.


----------



## sunny01 (17. Jun 2010)

Ich habe dem Administrator des Servers nochmal geschrieben ... ich weiß einfach nicht mehr was ich noch machen soll, damit sich das zeitlich alles ausgeht ... vielleicht kommt ja diesmal eine konstruktivere Antwort ...


----------



## faetzminator (17. Jun 2010)

Blöde Frage, aber warum crawlst du dir nicht alles per [c]wget[/c] o.ä. (rekursive Downloads und Beschränkung dieser möglich) und sammelst dann lediglich die notwendigen Daten? Da werden die Daten halt abgespeichert, aber du hättest das Crawlingproblem gelöst.


----------



## sunny01 (17. Jun 2010)

Das bringt mir genau was? Außer dass ich alles neu programmieren muss, wofür eigentlich keine Zeit mehr ist? 

Auslesen muss ich die Links doch so oder so, wenn da noch Zwischenspeichern auf der Festplatte oder sonstwas dazwischen ist, wird es doch auch nicht schneller!?
So nehme ich beim parsen halt gleich nur die Links mit, und nicht die ganzen Webseiten ... das würde ja noch viel länger dauern immer erstmal die ganze Seite herunterzuladen, alle Einzelseiten zu speichern, und dann nochmal drübergehen, und die Links auslesen um den Graphen zu bauen. 

Verstehe ich nicht.


----------



## faetzminator (17. Jun 2010)

...du hast endlich mal die Daten und kannst dich auf das Problem des indexieren konzentrieren - war nur eine Idee


----------



## sunny01 (17. Jun 2010)

Wenn ich die 500 Websiten mit ihren 10.000en Einzelseiten zuerst alle auf meinen Rechner lokal downloade, wird das mein Problem höchstens erschweren. Ich verstehe leider die Idee dahinter nicht. 

Das Indexieren würde dann auch wieder gleich laufen, wie jetzt auch, nur eben dass ich dann "nur mehr" lokale Zugriffe hätte über das FileSystem. Dafür habe ich statt einfach nur Links auszulesen ungefähr 5.000.000 pages auf meinen Rechner geladen, die ich überhaupt nicht brauche, was mit meiner Internetverbindung sicherlich Tage dauert und womit ich dann auch wieder von Vorne anfangen muss. Glaube nicht, dass die Zeitersparnis durch den lokalen Aufruf dann noch irgendetwas bringt. Denn die Zeit ist wohl schon abgelaufen, bevor ich überhaupt die 500 Seiten lokal auf den Rechner gezogen habe. 

Tut mir leid, komme nicht ganz dahinter wo Du den Vorteil siehst bzw. wo ich ihn nicht sehe.


----------



## Guest2 (17. Jun 2010)

Ich befürchte um eine teilweise Neuimplementierung wirst Du nicht umhinkommen. Das Problem wird die Rekursion innerhalb der getLinks() sein.  Bei einer 64Bit VM sind die Rücksprungadressen auf dem Stack auch 64Bit groß, dadurch knallt das vermutlich auf dem Server auch früher als bei Dir auf dem Rechner.

Und wenn Du dann schon dabei bist, mit Set, Map und Queue wird das viel einfacher.

Und da heute schon Donnerstag ist, das crawlen würde ich, von Deinem Quellcode und dem Deinem vermutlichen Kenntnisstand ausgehend, in etwa so aufbauen:

(Das bilden der Matrizen und die vollständige Behandlung der Links ist da allerdings nicht drin)


```
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;

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


public class Crawler {

    private final HTMLEditorKit editorKit = new HTMLEditorKit();

    private final Queue<URL>    toRead    = new ArrayDeque<URL>();
    private final Set<URL>      readed    = new HashSet<URL>();

    private final String        domain;

    private long                crawled   = 0;


    public Crawler(final String domain) {

        this.domain = domain;

    }


    public void fetch(final URL url) {

        toRead.add(url);

        while (toRead.size() > 0)
            try {

                fetchURL(toRead.poll());

            } catch (final IOException e) {

                e.printStackTrace();

            } catch (final BadLocationException e) {

                e.printStackTrace();

            }

    }


    private void fetchURL(final URL url) throws IOException, BadLocationException {

        BufferedReader reader = null;

        try {

            System.out.println(crawled + ": " + url);

            reader = new BufferedReader(new InputStreamReader(url.openStream()));

            fetchATAG(url, reader);

        } finally {

            crawled++;

            readed.add(url);

            if (reader != null)
                reader.close();

        }

    }


    private void fetchATAG(final URL url, final Reader reader) throws IOException, BadLocationException {

        final HTMLDocument htmlDoc = new HTMLDocument();
        htmlDoc.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
        editorKit.read(reader, htmlDoc, 0);

        String link;
        final HTMLDocument.Iterator iterator = htmlDoc.getIterator(HTML.Tag.A);
        while (iterator.isValid()) {

            link = String.valueOf(iterator.getAttributes().getAttribute(HTML.Attribute.HREF));

            if (link.startsWith("/"))
                link = url + link;

            if (link.contains(domain))
                if (!toRead.contains(link) && !readed.contains(link))
                    toRead.add(new URL(link));

            iterator.next();

        }

    }


    public static void main(final String[] args) throws MalformedURLException, IOException, BadLocationException {

        final Crawler crawler = new Crawler("google.de");
        crawler.fetch(new URL("http://www.google.de"));

    }

}
```

Gruß,
Fancy


----------



## sunny01 (17. Jun 2010)

Danke für Deinen Vorschlag, Fancy. 

Ich fühle mich mittlerweile nur mehr überfordert, habe schon die Nächte durchgemacht, kann nicht mehr denken. In Deinem Beispiel ist mir nicht klar, wie ich die ganze Indexierung und Verspeicherung der Adjazenzlisten bewerkstelligen soll, sodass ich dann Adjazenzmatrizen generieren kann. Nur zu wissen, ob der Link schon besucht war oder nicht, reicht ja für meine Aufgabenstellung nicht aus. 

Ich müsste mir das alles nochmal in Ruhe durchdenken, aber den kühlen Kopf dafür habe ich gerade nicht, weil ich nicht mehr glaube, dass sich das alles noch ausgeht. Ich werde mal versuchen, eine Pause zu machen, um dann nochmal darüber nachzudenken. Im Moment geht gar nichts mehr.


----------



## faetzminator (17. Jun 2010)

Dann macht man aus dem [c]Set<URL>[/c] eine [c]Map<URL, List<URL>>[/c] und man hat die Verbindungen.


----------



## fastjack (17. Jun 2010)

Ich denke auch, das eine Version 2 her muß, auch wenns noch eine Nacht wird  Wie Fancy schon erwähnte sind hier Maps und Co. besser, weil Du dann unnötiges Durchlaufen von Listen sparst. Damit findest Du nämlich einen Eintrag bereits in einem und nicht erst in n Schritten, im worst case soviele Schritte, wie die Liste gerade hatte... 
Wenn Du was replacen mußt, z.B. ../../../, kannst Du auch String.replace() verwenden, Du benötigst dann keine while-Schleife und viele substring-Aufrufe. 
Naja, als Java-Beginner ist es schon eine schwere Übung, trotzdem finde ich die Idee alle Links zu durchforsten und in einem Graphen zu halten sehr sehr nett 
Ich weis nicht, wie schnell HTMLEditorKit ist, aber Du kannst Links auch ganz leicht durch Verwendung von Regex finden. Leider habe ich nur ein PHP-Beispiel gefunden, das sich aber sehr leicht in Java übertragen sollte:

Reguläre Ausdrücke - Wie finde ich alle Links in einer HTML-Datei?

Solche Dienste sollten ansichtlich sehr schnell durchlaufen, vor allem, wenn sie permanent eingesetzt werden(um den Graphen aktuell zu halten), damit sie die auszuführende Maschine nicht allzulange belasten. Deshalb finde ich die Idee mit einem abgekoppelten Datei-Fetchvorgang auch nicht schlecht. Sind alle Links einer Website lokal gespeichert, springt der Graphendienst auf die lokalen Dateien an. Auch nyce, birgt allerdings die Gefahr, daß Du Dir irgendwann die Platte zuspeicherst. Du mußt also danach auch wieder automatisch aufräumen. 
Wenn Du Zeit hättest würde ich Dir empfehlen beide Varianten auszuprobieren, wenn Du keine Zeit hast, mußt Du die erste nehmen, die Fancy schon vorbereitet hat. Ansonsten Toi Toi Toi :toll:

P.S.: Ich habe mal mit meinem Sysop gesprochen und er meinte damals wäre kein Speicher kaputt gewesen. Das Problem bestand darin, das er zum einen Originalspeicher und zum anderen Fremdspeicher verbaut hatte. An sich kompatibel, aber unter bestimmten Umständen (Last) hatte das Mainboard Probleme den Fremdspeicher anzusprechen.


----------



## Guest2 (17. Jun 2010)

Noch ein Nachtrag zu meinem letzten Beispiel: In Zeile 101 ist leider ein Fehler. 
Es wird mit Strings geprüft und URLs sind im Set -> Zeile 101 wird immer zu true ausgewertet. 


```
final URL adress = new URL(link);

if (link.contains(domain))
    if (!toRead.contains(adress) && !readed.contains(adress))
        toRead.add(adress);
```

Etwa so sollte es gehen.

Gruß,
Fancy


----------



## FArt (18. Jun 2010)

Ich wiederhole mich auch noch mal schnell: baue die Rekursion aus! Der Umbau ist minimal... eine Collection für die neuen Links, eine Collection für besuchte Links, eine große Schleife... nimm (so lange neue Links da sind oder anderes Abbruchkriterium) nächsten neuen Link, ziehe den Link von neu nach nicht neu um, lese Seite, nimm dessen Links und klassifiziere sie nach neu oder nicht neu ...


----------



## faetzminator (18. Jun 2010)

Wie bereits erwähnt, wenn man das [c]Set[/c] zu einer [c]Map[/c] umbaut, kann man sich so die Verbindungen speichern - hier als Beispiel in Guest2s Code (siehe die [c]Map[/c] und [c]main()[/c]):

```
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

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

public class Crawler {

    private final HTMLEditorKit editorKit = new HTMLEditorKit();
    private final Queue<URL> toRead = new ArrayDeque<URL>();
    private final Map<URL, Set<URL>> readed = new HashMap<URL, Set<URL>>();
    private final String domain;
    private long crawled = 0;

    public Crawler(final String domain) {
        this.domain = domain;
    }

    public void fetch(final URL url) {
        toRead.add(url);
        while (toRead.size() > 0) {
            try {
                fetchURL(toRead.poll());
            }
            catch (final IOException e) {
                e.printStackTrace();
            }
            catch (final BadLocationException e) {
                e.printStackTrace();
            }
        }
    }

    private void fetchURL(final URL url) throws IOException, BadLocationException {
        BufferedReader reader = null;
        try {
            System.out.println(crawled + ": " + url);
            crawled++;
            readed.put(url, new HashSet<URL>());
            reader = new BufferedReader(new InputStreamReader(url.openStream()));
            fetchATAG(url, reader);
        }
        finally {
            if (reader != null) {
                reader.close();
            }
        }
    }

    private void fetchATAG(final URL url, final Reader reader) throws IOException, BadLocationException {
        final HTMLDocument htmlDoc = new HTMLDocument();
        htmlDoc.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
        editorKit.read(reader, htmlDoc, 0);

        String link;
        final HTMLDocument.Iterator iterator = htmlDoc.getIterator(HTML.Tag.A);
        while (iterator.isValid()) {
            link = String.valueOf(iterator.getAttributes().getAttribute(HTML.Attribute.HREF));
            if (link.startsWith("/")) {
                link = url + link;
            }
            final URL adress = new URL(link);
            if (link.contains(domain) && !toRead.contains(adress) && !readed.containsKey(adress)) {
                toRead.add(adress);
                readed.get(url).add(adress);
            }
            iterator.next();
        }
    }

    public static void main(final String[] args) throws MalformedURLException, IOException {
        final Crawler crawler = new Crawler("google.de");
        crawler.fetch(new URL("http://www.google.de"));
        
        System.out.println("saved urls:");
        for (Map.Entry<URL, Set<URL>> entry : crawler.readed.entrySet()) {
            System.out.print(entry.getKey());
            System.out.println(":");
            for (URL url : entry.getValue()) {
                System.out.print("- ");
                System.out.println(url);
            }
        }
    }
}
```


----------



## sunny01 (18. Jun 2010)

Hallo zusammen, 

vielen lieben Dank für eure viele und geduldige Hilfe. 
Gestern hatte ich absolut keinen Kopf mehr, mich um eine Neuprogrammierung zu kümmern. Sorry ... ich war schon sehr verzweifelt. 

In der Zwischenzeit hatte mir heute morgen der Administrator zurückgeschrieben, dass er mir Java 5 am Server parallel installiert hat (wie es ja auch hier vorgeschlagen wurde). Habe es dann damit ausprobiert, und es läuft bisher alles problemos (schon seit heute Morgen, der kritische Bereich wo sonst immer der Fehler kam, ist schon lange überschritten). Ich hoffe, das bleibt nun so ... bin immer noch sehr am bibbern ... 

Liebe Grüße
sunny


----------



## crefeld (21. Jun 2010)

sunny01 hat gesagt.:


> 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
> [..]
> 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 ...



Das ist natürlich nicht sehr freundlich von Eurem Sysadmin, hat aber einen wahren Kern: Leider produzieren viele mit Hilfe von IDE & Konsorten "irgendwie" Code ohne Kenntnis der Umgebung mit entsprechend wenig soliden Ergebnissen. Aber das nur am Rande.

Options, die der Java-Maschine mitgegeben werden, können vielfältiger Natur sein. Dementsprechend lohnt es sich schon, was Java im allgemeinen ( java - the Java application launcher ) und der Hotspot-Compiler in Deiner Umgebung im speziellen ( Java HotSpot VM Options ) so kennt. Im übrigen sollte nach meiner unmaßgeblichen Meinung die primäre Anlaufstelle bei grundsätzlichen Java-Problemen Java SE 6 Documentation und nicht Google & Co. sein.


----------



## fastjack (22. Jun 2010)

Kleiner Nachtrag: Im aktuellen Java-Magazin gibt es einen interessanten Beitrag zu einer hochoptimierten Graphendatenbank.


----------

