"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
 

sunny01

Aktives Mitglied
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

Gesperrter Benutzer
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

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

sunny01

Aktives Mitglied
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.
 
G

Guest2

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

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

Aktives Mitglied
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.
 
Zuletzt bearbeitet:

fastjack

Top Contributor
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.
 
G

Guest2

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

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

Top Contributor
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

Gesperrter Benutzer
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]):
Java:
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

Aktives Mitglied
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

Neues 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 :(
[..]
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.
 

Ähnliche Java Themen


Oben