StackOverFlow - SocketTimeoutException

Status
Nicht offen für weitere Antworten.

phlox81

Mitglied
Nach dem mein Crawler nun lauffähig ist,
und sich auch nicht mehr verläuft, hab ich das nächste Problem,
und keinen blassen Schimmer woran es liegen könnte:

Code:
java.lang.StackOverflowError
	at java.net.SocketTimeoutException.<init>(Unknown Source)
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.read(Unknown Source)
	at java.net.SocketInputStream.read(Unknown Source)
	at java.io.FilterInputStream.read(Unknown Source)
	at java.io.PushbackInputStream.read(Unknown Source)
	at org.apache.commons.httpclient.HttpConnection.isStale(HttpConnection.java:533)
	at org.apache.commons.httpclient.HttpConnection.isOpen(HttpConnection.java:468)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:660)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:529)
	at HTTPGet.GetRequest(HTTPGet.java:25)
	at Crawler.crawl(Crawler.java:51)
	at Crawler.crawl(Crawler.java:98)
	at Crawler.crawl(Crawler.java:104)
^So sieht es aus, wenn ich in HTTPGet Request keinen Timeout setze, sondern dies global im Header
der Helfer klasse tue.

Code:
java.lang.StackOverflowError
	at java.lang.Exception.<init>(Unknown Source)
	at java.io.IOException.<init>(Unknown Source)
	at java.io.InterruptedIOException.<init>(Unknown Source)
	at java.net.SocketTimeoutException.<init>(Unknown Source)
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.read(Unknown Source)
	at java.net.SocketInputStream.read(Unknown Source)
	at java.io.FilterInputStream.read(Unknown Source)
	at java.io.PushbackInputStream.read(Unknown Source)
	at org.apache.commons.httpclient.HttpConnection.isStale(HttpConnection.java:533)
	at org.apache.commons.httpclient.HttpConnection.isOpen(HttpConnection.java:468)
	at org.apache.commons.httpclient.HttpMethodBase.processRequest(HttpMethodBase.java:2653)
	at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1093)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:675)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:529)
	at HTTPGet.GetRequest(HTTPGet.java:26)
	at Crawler.crawl(Crawler.java:51)
	at Crawler.crawl(Crawler.java:98)

^So siehts mit jeweiligem gesetzten Timeout aus.

Die Klasse in der das Ganze stattfindet sieht so aus:
Code:
public class HTTPGet
{
	HttpClient http; 
	public  HTTPGet(){
		http = new HttpClient();
		http.setState(new HttpState());
    	http.getHostConfiguration().setProxy("mmoproxy", 8080);
    	UsernamePasswordCredentials upc = new UsernamePasswordCredentials();
    	upc.setPassword("");
    	upc.setUserName("");
    	http.getState().setProxyCredentials(null,null ,upc);
	}
	public String GetRequest(String request){
		try
		{
			//if(http.getHttpConnectionManager().getConnection(http.getHostConfiguration()).isOpen())
			{
			http.setTimeout(10000);
		    	//http.getHostConfiguration().setProxy("mmoweb", 8080);
		    	HttpMethod method = new GetMethod(request);
		    	method.setDoAuthentication(true);
			http.executeMethod(method); 
			String str = method.getResponseBodyAsString();
			method.releaseConnection();
			return str;
			}
			//return "";
		}
		catch (Exception e)
		{
			System.out.print("GetRequest: "+e.toString());
		}
		return null;
	}
}

Ich muss dazu wohl sagen, das der Fehler erst nach einiger Zeit auftritt,
vorher läuft alles reibunglos. Erst ab einer bestimmten Tiefe bzw. Laufzeit
tritt der Fehler auf.

Hat jemand eine Idee woran es liegen könnte ?
Ist es vielleicht der Speicherverbrauch ?

Devil
 
Schau doch mal nach Endlosschleifen. Wenn du dort Speicher verbrauchst, kommst du schnell zu einem StackOverflow.
 
Prinzipiell könntest du auch mal den Speicher für die VM hochsetzen, aber das wird dann nur dazu führen, dass dein Programm etwas später abstürzt. Die VM rufst du dann so auf:
java -Xms256m -Xmx256m -XX:MaxPermSize=256m

Versuch möglichst viele Objekte die du nutzt nur einmal zu initialisieren und sie nicht ständig zu verwerfen und neue zu erzeugen. Das hilft meistens am besten.
 
In Java gibts ja leider kein delete 😉

Lokale Variablen werden aber doch sofort nach der Funktion wieder gekillt, richtig ?
 
System.out.print("GetRequest: "+e.toString());

liest du das immer mit?

wenn die nämlich fliegt, wird ja uU die Connection nicht geschlossen
 
devil81 hat gesagt.:
In Java gibts ja leider kein delete 😉

Lokale Variablen werden aber doch sofort nach der Funktion wieder gekillt, richtig ?

Delete gibt's nicht, das tut alles der Garbage Collector für dich. Der läuft allerdings in einem separaten Thread und sucht nach benutzten Objekten, indem er den Referenzgraphen auf und abläuft; nicht erreichbare Objecte werden zu Löschung markiert. Wenn du zu schnell zu viele riesige Objekte erzeugst, hat er eventuell nicht genug Zeit. "Sofort" ist also etwas zu hoch gegriffen.

Ich hab mal ein Programm geschrieben, dass die Festplatte nach mp3 absucht, die Tags ausliest und alles in XML vermerkt: auch da kamen ne ganze Menge von temporären Objekten zusammen, die zwar nach Methodenaufruf "weg" waren, aber scheinbar das Programm trotzdem durch StackOverflows zu Absturz brachten. Durch Verringerung der temporären Objekte pro Suchzyklus habe ich das Problem gelöst. Vielleicht war's auch nur Glück!? :bae:
 
Bleiglanz hat gesagt.:
System.out.print("GetRequest: "+e.toString());

liest du das immer mit?

wenn die nämlich fliegt, wird ja uU die Connection nicht geschlossen

Nein, die ist noch nie geflogen, aber danke für den Hinweis 🙂
 
So, hab jetzt angefangen meinen Code zu optimieren, möglichst wenig
Lokale Objekte (bin das von C++ gewohnt :roll: ), einiges hab ich statisch gemacht,
und kann jetzt meine Testseite schon auf 4 facher Tiefe crawlern.
Bei 5 Facher Tiefe fliegt er allerdings immer noch raus wegen Stackoverflow,
sind auch ein paar mehr links :lol: (Logdatei 3fache tiefe = 7 Kb, 4 Fache 27 Kb, 5 fache bis Crash 52 kb).

Meine Crawl Funktion ist momentan noch rekursiv, würde es etwas bringen
sie iterativ zu machen ?
Welche Optimierungsmöglichkeiten gibt es noch ?

Devil
 
willst du eine Webseite "crawlen"?

a) schmeiss mal den konstruktor in HTTPGet weg und mach eine einzige statische Methode getPage, mir der du dir eine Page abholst und die alles innerhalb der Methode erledigt

b) machs iterativ, ich würde das eher so machen

seiteninhalt holen
alle Links extrahieren und in datenbank schreiben
in der datenbank ein feld "zuletzt_geholt" als Datetime
dann fertig

dann lässt du den crawler über diese datenbank laufen, holst dir alle seiten, extrahierst die links und schreibst sie wieder in die DB
und bist fertig

auf diese weise würde die Tabelle immer weiter anwachsen, du könntest ein Timeout setzten (und oder den lastModified Header mit abspeichern) und so gezielt "neu laden"

die crawl methode würde dann so aussehen [kannst du ja in eine endlosschleife packen...]
Code:
resultset = SELECT FROM links // ggf. mit WHERE
while(rs.next){
    hole seite
    extrahiere alle Links
    insert aller gefundenen links in die tabelle (mit zuletzt_geholt=NULL)
}
als "Seed" musst du initial natürlich mindestens eine URL in deine Tabelle einfügen
 
Bleiglanz hat gesagt.:
willst du eine Webseite "crawlen"?

a) schmeiss mal den konstruktor in HTTPGet weg und mach eine einzige statische Methode getPage, mir der du dir eine Page abholst und die alles innerhalb der Methode erledigt

b) machs iterativ, ich würde das eher so machen

seiteninhalt holen
alle Links extrahieren und in datenbank schreiben
in der datenbank ein feld "zuletzt_geholt" als Datetime
dann fertig

dann lässt du den crawler über diese datenbank laufen, holst dir alle seiten, extrahierst die links und schreibst sie wieder in die DB
und bist fertig

auf diese weise würde die Tabelle immer weiter anwachsen, du könntest ein Timeout setzten (und oder den lastModified Header mit abspeichern) und so gezielt "neu laden"

die crawl methode würde dann so aussehen [kannst du ja in eine endlosschleife packen...]
Code:
resultset = SELECT FROM links // ggf. mit WHERE
while(rs.next){
    hole seite
    extrahiere alle Links
    insert aller gefundenen links in die tabelle (mit zuletzt_geholt=NULL)
}
als "Seed" musst du initial natürlich mindestens eine URL in deine Tabelle einfügen

Jein, ich schreibe einen WAP Crawler.
Momentan bau ich damit einen Baum auf und speicher darin die Links.
An eine DB hab ich noch nicht gedacht, wäre auch nicht die beste Lösung, da
ich nicht weis ob diese auf der Zielplattform dann zur Verfügung steht.

Devil
 
nimm eine embedded db wie z.B. HSQL

problem ist doch, dass du beim rekursiven crawlen u.U. einen RIESIGEN Baum aufbaust

wenn nur 10 Links auf jeder seite sind:

10 gefunden auf level 1
100 gefunden auf level 2
1000 gefunden auf level 3
10000 gefunden auf level 4

d.h. wenn du rekursiv im level 4 bist, dann würden ja 1000 Einträge auf dem Stack rumliegen, das ist irgendwie unschön...

BTW: was solln das crawlen bringen, wenn alles im speicher ist? musst du doch eh irgendwo abspeichern??
 
Natürlich soll ich nicht nur Last generieren :lol:

Die Klasse Crawler besitzt eine variable Reporter,
welche über notify aufgerufen wird, und dann jeweils

das Ergebnis z.b. in eine Datei schreibt. (Es sind mehrere Reporter möglich).

Im übrigen hab ich nun die sache auf Iterativ umgeschrieben,
und das bringt schon mal einiges 😀
Level 5 Macht er nun anstandslos.
Hm, 6 fach ist nun auch kein Problem(insgesamt 6592 Links), ich glaub die Rekursion in
Java ist ein absolutes DON'T *g*

Devil
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben