# htmlCode einlesen, Speicherüberlauf? zu viel code?



## Kumaro (31. Okt 2011)

Guten Abend ,

ich habe ein kleines Problem und trotz intensiver Suche und probierens finde ich keine Lösung daher hoffe ich auf eure hilfe:

Ich bin dabei ein tool zu schreiben was einen link bekommt und dann die daten der website als String 
einliest. Das klappt alles auch soweit ganz gut.

Jetzt ist es aber so dass mehrere Seiten (links) direkt hintereinander in einer schleife eingelesen werden müssen und genau DA ist das Problem.

Lass ich nur einen Link einlesen klappt alles wie es soll. Lass ich zwei links einlesen macht er mit dem ersten was er soll und dann steht das Programm....entweder dauert es seeeeehr lange oder es tut sich nichts mehr (was es genau ist kann ich leider nicht sagen) . 

Das ist der CodeAusschnitt


```
/**Scanning First SensorSites to get HTML Format**/

WebsiteScanner sensorScanner = new WebsiteScanner(htmlCodeSensor, linkAfterString);

//anzahl der links
arrayLength = sensorScanner.getHtmlFormat().length;
			
	String[] htmlSensorLinks = new String[arrayLength];
	      for(int i=0; i < arrayLength ; i++){
		
                       //holt sich von einer anderen Seite die links die er durchsuchen soll
                        htmlSensorLinks[i] = sensorScanner.getHtmlFormat()[i];
				}



/**Scanning SensorSites with Data**/
	
//startet die instanz des Readers der die Methode enthält die den html code einliest
WebsiteReader dataSite = new WebsiteReader();

//String Array welches die html Codes die eingelesen wurden aufnehmen soll 	
String[] htmlCodeDataSite = new String[arrayLength];
	
             //durchläuft die anzahl der vorhandenen links die eingelesen werden sollen
	for(int i=0; i < arrayLength; i++){
	               
                             //liest die seiten hinter den links ein
                             htmlCodeDataSite[i] = dataSite.getStrFromUrl(htmlSensorLinks[i]);
		
                   //durchsucht den html code nach den wichtigen daten...			
                   WebsiteScanner sensorDataScanner = new WebsiteScanner(htmlCodeDataSite[i], dataStartTag, dataEndTag, timeStartTag, timeEndTag);
	    
                    //...und erzeugt eine arrayList mit den wichtigen daten in dieser Methode
                    sensorDataScanner.scanForSensorData();
				}
```

Wenn ich den unteren Teil, also die schleife nur bis 1 laufen lasse klappt alles super, sobald er das für mehrere nacheinander machen soll ist es vorbei und ersteht ... 

Woran kann das liegen? Zwar sind es jeweils immer mehr als 120.000 Zeilen aber der Speicher kann ja wohl kaum voll sein oder?  

Was kann ich machen?

Sorry, ich hoffe ich konnte mich verständlich genug ausdrücken ^^...

Ich hoffe sehr auf eure Hilfe.

vielen Dank im voraus


----------



## mfernau (31. Okt 2011)

Das sieht mir jetzt alles doch recht aus dem Zusammenhang herausgerissen aus.
Bist du denn Deinen Code schon mal mit einem Debugger druchgegangen? Speicherüberlauf klingt nach einer Endlosschleife die ständig irgendwo Daten hinein pumpt. Was genau bekommst Du denn für einen Fehler nach der langen Wartezeit?

Ich würde Deinen Code mal Zeile für Zeile mit einem Debugger durchgehen und schauen ob auch überall das drin steht was Du erwartest/denkst.


----------



## winSharp93 (31. Okt 2011)

Hallo Kumaro,

OutOfMemory oder StackOverflow?

Evtl. liest du auch einfach tatsächlich so viel ein, dass der Eindruck entsteht, dein Programm habe sich aufgehängt.
Führst du für jede der 120.000 Zeilen einen erneuten Webrequest durch?


----------



## Kumaro (1. Nov 2011)

Guten Morgen,

danke das ihr mir helfen wollt.

Also ich bin bisher noch nicht den code mit dem debugger durchgegangen da ich bei eclipse damit noch nicht recht vertraut bin, .

Was genau meinst du mit webrequest? Meinst du den zugriff auf die seite damit? Der findet nur einmal pro link statt und liefert den html code als string zurück.

Ja vermutlich hängt sich das programm nicht auf, ich bekomme ja auch keine fehlermeldungen, es dauert nur unwahrscheinlich lange so dass das ganze keinen sinn mehr macht.

Wie gesagt wenn ich nur eins von beiden einlese, läuft es super und dauert nicht mal 20 sec. Bei 2 kann es doch dann nicht 20 min und länger dauern oder??

Das müsste doch auch nacheinander in der Schleife genauso schnell funktioniren oder nicht? 

Ich weiß keinen rat...


----------



## Kumaro (1. Nov 2011)

Also das die html seiten so groß sind liegt daran dass da Sensormessungen aufgelistet sind und das sind jede menge .... Und mir geht es darum diese messungen einzulesen und auszuwerten.

Ich bekomme leider ja keinen fehler... zumindest nicht innerhalb der ersten 20 min (länger habe ich ihn noch nicht rödeln lassen).... 
Wenn ich mir meine speicherauslastung ansehe bin ich gerade mal bei 2 GB von 8 GB und der prozessor ist fast bei 0%.... 

Hier noch etwas code viel ist es dann offensichtlicher für euch:

so sieht der htmlcode aus (ein kleiner ausschnitt)


```
<table id="information">
            <thead>
            <tr>
            <th>Timestamp</th>
            <th>Readings(13827)</th>
            </thead>
            <tbody>
            
                <tr>
                    <td>
                        2011-09-27 15:37:05.0
                    </td>
                    <td align="center">
                        18.0
                    </td>
                </tr>
            
                <tr>
                    <td>
                        2011-09-27 16:26:38.0
                    </td>
                    <td align="center">
                        22.0
                    </td>
                </tr>
```


Relevant in der Main ist eigentlich nur der Ausschnitt

```
/**Scanning SensorSites with Data**/
			WebsiteReader dataSite = new WebsiteReader();
			String[] htmlCodeDataSite = new String[arrayLength];
	
		for(int i=0; i < 2; i++){
		htmlCodeDataSite[i] = dataSite.getStrFromUrl(htmlSensorLinks[i]);
					
	WebsiteScanner sensorDataScanner = new WebsiteScanner(htmlCodeDataSite[i], dataStartTag, dataEndTag, timeStartTag, timeEndTag);
						sensorDataScanner.scanForSensorData();
				}
```

--> Wobei htmlSensorLinks_ einfach nur die ganzen links enthält die nacheinander eingelesen werden sollen.


Damit werden die seiten eingelesen und als String zurück geleifert.


		Java:In die Zwischenablage kopieren


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;


public class WebsiteReader {
	
	/**Constructor**/
	public WebsiteReader(){ 
							
	}


	public String getStrFromUrl(String surl) {
	      
		final String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12";
	      
	      try {
	         URL url = new URL(surl);
	         URLConnection conn = url.openConnection();
	         conn.addRequestProperty("User-Agent", userAgent);
	 
	         BufferedReader in = new BufferedReader(new InputStreamReader(
	               conn.getInputStream()));
	         String str;
	         StringBuilder builder = new StringBuilder(1024);
	         while ((str = in.readLine()) != null) {
	            builder.append(str);
	            builder.append("\n"); //damit es hinterher auch so aussieht wie vorher ;-) 
	         }
	         in.close();
				         //Test-Output
				         //System.out.println(builder.toString());
	         
			System.out.println("Seite wurde eingelesen.");	         
			return builder.toString();
	      
	      } catch (MalformedURLException e) {
	         System.out.println(e.getMessage());
	      
	      } catch (IOException e) {
	         System.out.println(e.getMessage());
	      }
		return "Error";
	   }
	
}



Damit werden die Daten aus dem html code extrahiert und zurückgeliefert


		Java:In die Zwischenablage kopieren


public ArrayList<String> scanForSensorData(){
		
String keinHTML = htmlCodeData.replaceAll("\\<.*?\\>", "");    //ENTFERNT HTML CODE!
		
		String split[] = keinHTML.split(" ");
		ArrayList<String> sensorDataList = new ArrayList<String>();
		
		for(int i=0; i < split.length; i++){
		if(!split[i].trim().equals("")){   //entfernt alle leerzeichen vor und hinter dem String
		// entfernt die Absätze (\n) hinter den strings
                                    sensorDataList.add(split[i].trim());	   			
                                        }
			
		}
									
				//Test-Output
				for(int k=0; k < sensorDataList.size(); k++){
										System.out.println(sensorDataList.get(k));
									}	 
 return sensorDataList;
		
	}


So sieht nach der extrahierung die Ausgabe also díe ArrayList aus:
"
2011-09-27 
15:37:05.0 
18.0
2011-09-27 
16:26:38.0
22.0
"
usw.

Wie gesagt für einen Link klappt das wunderbar. für zwei schon nicht mehr ._


----------



## Gossi (1. Nov 2011)

Kumaro hat gesagt.:


> 1:
> Also ich bin bisher noch nicht den code mit dem debugger durchgegangen da ich bei eclipse damit noch nicht recht vertraut bin, .
> 
> 2:
> Was genau meinst du mit webrequest? Meinst du den zugriff auf die seite damit? Der findet nur einmal pro link statt und liefert den html code als string zurück.



Zu 1:
Dann solltest du evtl. mal ein bisschen damit rumspielen, mach dir nen kleines Beispiel mit ner for-Schleife und mach nen Breakpoint im Kopf der for-Schleife ([c]for(int i = 0; i < 10; i++)[/c]) und schau dir das ganze mal im Debugger an.

Zu 2:
Evtl. ist der Code auch zu lang für einen String?

Edit:



Kumaro hat gesagt.:


> Relevant in der Main ist eigentlich nur der Ausschnitt
> 
> ```
> /**Scanning SensorSites with Data**/
> ...


----------



## Kumaro (1. Nov 2011)

hi, ja werd mich mit dem Debugger mal beschäftigen.

Aber merkwürdig ist doch das es bei einem link klappt und bei 2 hintereinander nicht mehr.
Er gibt mehr auch die ersten daten (vom ersten link) aus (weniger 20 sec) und dann passiert (scheinbar) nichts mehr wo er eigentlich den zweiten link einlesen sollte.

Sorry  "Dann solltest du vielleicht schreiben for(int i=0; i < htmlCodeDataSite.length; i++) "
Das hab ich natürlich drin stehen, nur testeshalber hatte ich mal 2 reingeschrieben.


Hast du viell noch eine idee? 

Danke für eure Mühe.


----------



## Gossi (1. Nov 2011)

Kumaro hat gesagt.:


> hi, ja werd mich mit dem Debugger mal beschäftigen.
> 
> Aber merkwürdig ist doch das es bei einem link klappt und bei 2 hintereinander nicht mehr.
> Er gibt mehr auch die ersten daten (vom ersten link) aus (weniger 20 sec) und dann passiert (scheinbar) nichts mehr wo er eigentlich den zweiten link einlesen sollte.
> ...



Leider habe ich mit I/O noch nicht so wirklich beschäftigt, ich bin hiermeit also ersmal am ende, sorry


----------



## mfernau (1. Nov 2011)

Das es mit einem Schleifendurchgang funktioniert und mit dem nächsten nicht mehr kann zweierlei Gründe haben weswegen ich Dir einfach dringend ans Herz legen möchte den Debugger zu verwenden. Ein Debugger ist nichts magisches und kein Buch mit sieben Siegeln. So'n Ding gehört in den täglichen Gebrauch eines Entwicklers denn das Rätselraten warum und wieso ein Stück Code nicht funktioniert, dauert im Regelfall länger als mal eben mit dem Debugger durch zu gehen und zu sehen wo der Hase im Pfeffer liegt.

Zwei mögliche Gründe die mir gerade einfallen wieso Dein Code nicht nach Deinen Erwartungen funktioniert:
1. Entweder stehen Deine Verarbeitungsklassen irgendwie miteinander in Verbindung und beim zweiten Durchgang stehen irgendwelche Variablen/Pointer nicht dort wo Du es vermutest (was hier aber gerade nicht so danach aussieht, auch wenn ich nicht weiss was für ein Konstruktor Du bei WebsiteScanner verwendest)
2. Oder vielleicht mach die url, die Du mit Deinem zweiten Durchgang einliest, irgendwie Probleme.

Es wäre einfach ungemein hilfreich zu wissen an welcher Stelle Dein Programmcode diese ewig langen Pausen einlegt. Das bekommst Du entweder nur durch viele System.out.println()'s heraus. Einfach mal an jeder interessanten Verarbeitungsstelle einen eindeutigen Output plazieren (also einen Output der Dir auch sagt an welcher Stelle im Code er sich gerade befindet. Ein "hallo" wäre da nicht gerade aussagekräftig ), damit Du auf der Konsole siehst ab wann augenscheinlich nichts mehr passiert. Alternativ würde ein Debugger genauso helfen ohne das Du Deinen Code damit vollspicken musst.

Grüße


----------



## Kumaro (1. Nov 2011)

Hi danke *mfernau*, wenn ich nachher zu Hause bin werde ich mich mal auf die Pfade des Debugger begeben und mal schauen ob ich raus bekommen an welcher Stelle er sich dann "aufhängt".

Wenn ich die Stelle gefunden habe werde ich noch mal Bericht erstatten und vielleicht weißt du ja dann auch (mehr als ich vermutlich) was genau das Problem sein kann ^^.

Danke schon mal


----------



## Kumaro (1. Nov 2011)

Guten Abend,

also ich habe jetzt mal den Debugger durchlaufen lassen und stoße in der Klasse: WebsiteReader und der Methode: getStrFromUrl(String surl) auf folgendes Problem.

Wenn ich an der Stelle (siehe Bild1) bin und dann einen Step weiter gehe bekomme ich jede Menge Exceptions (siehe Bild2), diese kann ich mit "next Step" aber alle durchgehen und dann läuft das Programm erstmal weiter.

Leider kann ich damit nicht so recht was anfangen, normal ist das doch nicht oder?

Bild1






Bild2


----------



## Marco13 (1. Nov 2011)

Doch, vielleicht: Wenn du dort "Step into" machst, versucht er in einer der Klassen zu hüpfen, und dann wirft der Debugger ggf. eine ClassNotFoundException oder so... Hangle dich am besten erstmal nur durch _deinen_ Code (ggf. eben "Step over" oder "Run to cursor") ...


----------



## Kumaro (1. Nov 2011)

mh ok, hab das mit "step over" mal übersprungen aber jetzt hab ich bei :


```
while ((str = in.readLine()) != null) {
	            builder.append(str);
	            builder.append("\n"); //damit es hinterher auch so aussieht wie vorher ;-) 
	         }
```

aus dem WebsiteReader das problem das ich mit "step  into" oder "step over" ja jeden einzelnen schritt machen muss... hier geht er ja jede Zeile des html Codes durch (und das ist zu viel)
Wie kann ich über die while schleife drüber springen??

Wenn ich das versuche durchzugehen (finger auf der F5 taste für "step into" lasse ^^) dann hört er bei zeile 16000 irgendwas auf und es passiert nichts mehr... heißt das das dort der Fehler liegt?


Sorry für die vielen dummen Fragen ^^.


----------



## Marco13 (1. Nov 2011)

Hab' jetzt zwar nicht den ganzen Thread im Detail durchgelesen, aber mit einem KSKB+Beispieldatei wäre das Problem sicher schon gelöst....


----------



## mfernau (1. Nov 2011)

Kumaro hat gesagt.:


> Wenn ich das versuche durchzugehen (finger auf der F5 taste für "step into" lasse ^^) dann hört er bei zeile 16000 irgendwas auf und es passiert nichts mehr... heißt das das dort der Fehler liegt?



16000?? Wie groß ist denn die html-datei... Das ist ja schon recht ordentlich..

Wenn Du die While-Schleife überspringen willst, dann setze doch einfach während Du beim Debuggen bist mit einem Doppelklick einen weiteren Breakpoint direkt nach der Schleife und drücke den Resume-Button. Dann springt er zum nächsten Breakpoint. Wenn er das nicht mehr tut ist der Fehler während der Verarbeitung in der while-schleife.
Sollte dies der Fall sein könnte das Problem mit dem "in.readLine()" auftreten. 
in.readLine() liest bis zum nächsten Zeilenende oder liefert null, wenn es nichts mehr zu lesen gab. Sollte aber die Verbindung noch aktiv sein und wird noch auf Daten gewartet, blockiert in.readLine() so lange bis entweder die Verbindung geschlossen wird oder bis wieder weitere Daten kommen. Könnte in deisem Fall vielleicht ein Problem mit der Verbindung zu dem Server auftreten von dem Du die Daten liest?
Evtl schon mal manuell versucht diese Daten herunter zu laden (mit telnet, wget, browser...)?


----------



## Kumaro (1. Nov 2011)

Ok, ich bekomm hier graue Haare, ich weiß nicht was das Problem ist ....

Ich würde mich rieeesig freuen wenn jmd Lust hat das bei sich mal nachzustellen. Ich habe mal eine kleines Testprogramm dazu gemacht in der Hoffnung das sich das Problem so besser eingrenzen lässt... aber ich kann es nicht finden.

Hier der Code dafür:

https://rapidshare.com/files/930201439/Test.rar

Wär echt cool wenn du dir das mal anschauen magst *Marco13* .


----------



## mfernau (1. Nov 2011)

Der Code funktioniert bei mir soweit (auch wenn ich nicht Marco13 bin  )


----------



## Kumaro (1. Nov 2011)

hehe , oh mir ist ein *FEHLER* unterlaufen 

Hab vergessen in der schleife  wieder auf 2 zu stellen:


```
for(int i =0; i < 2; i++){   //in der main
```


Sorry sorry ^^....
Bitte änder das mal und dann probier es erneut. Wie gesagt bei einem link gehts, ab zwei nicht mehr.

Auch dir vielen vielen Dank


----------



## mfernau (1. Nov 2011)

Hätte ich dazu erwähnen sollen dass ich das bereits gemacht hatte 
Also bei mir steht quasi:

```
....
Seite 1 wurde erfolgreich eingelesen!
...
....
Seite 2 wurde erfolgreich eingelesen!
```

edit: Und das alles innerhalb ein paar Sekunden
edit2: Aber hier passieren ja gar nicht die interessanten Dinge. Alles das was Du mit Deinem WebsiteScanner machst fehlt ja hier


----------



## Kumaro (1. Nov 2011)

höö?

Bei mir nicht ....   

bei mir kommt Seite 1 eingelesen und dann passiert ewig nichts.... ..

Woran kann das liegen? Eclipse? Rechner(6x 2,8 GHz, 8 GBRam - daran sollte es nicht liegen ^^) ??


edit:  Ja das sollte eigentlich ja auch nicht das problem sein...das sollte gehen, denk ich ^^ hab nur das genommen da ich vermutete das da das problem ist und da es einzeln ja auch nicht geht....mh

edit2: Hab dir mal ne PM geschrieben....

*edit3:* Jetzt gings bei mir auch?!? Hä? Kannst du es mal mehrmals laufen lassen...das funzt irgendwie nur sporadisch... ich bekomm hier nen rappel


----------



## mfernau (1. Nov 2011)

Riecht immer mehr nach nem verbindungsspezifischen Problem wenn's mal geht und mal nicht...
Wie gesagt: in.readLine() blockiert bis Daten kommen. Kommen keine Daten mehr weil Deine Verbindung zu diesem Server irgendwie nicht richtig funktioniert wartest Du im Zweifel bis morgen... Das hat man auch hin und wieder mal wenn man im Browser eine Seite offen hat bei der ständig die Laden-Animation (beim FF z.b. der rotierende Kreis) aktiv ist...


----------



## bERt0r (2. Nov 2011)

Wenn du so eine Riesen datei auslesen willst, stellt sich die Frage ob die Vorgangsweise, das ganze am anfang einzulesen überhaupt sinnvoll ist. Du könntest mit einem HTML parser einfach die <a> tags nach der Reihe durchgehen und einzeln direkt nach dem Lesen abarbeiten.


----------

