Out of Memory - Zuviele Objekte?

Goosefraba

Mitglied
Hallo!

Ich schreibe gerade ein Syncronisations-Tool für Access-Datenbanken und treffe laufend auf neue Probleme. Nun habe ich endlich die Treiber-Defizite von MS-Access-Treibern umgangen, nun auch schon das nächste Problem.

Ich lege für jedes Tupel (Zeile in einer Tabelle) ein Objekt "Tupel" an. Dieses hat eine ArrayList vom Typ Column und speichert dort für jedes Attribut, den Namen und den Wert. (Legt sich für jedes Attribut ebenfalls ein neues Objekt vom Typ Column an).

Sobald ich (innerhalb des Tupels mittels Methode) ein neues Column in die Column-Liste des Tupels adde, hängt sich quasi alles auf und es kommt zu einer OutOfMemory Fehlermeldung.

Die Routine (teilweise auskommentiert zwecks Fehlersuche; idente Schleife für die "Slave-DB" gibt es auch) welche mir die Tupel-Objekte erstellt
Code:
	public String getDifferentEntries(String chooseTable) throws SQLException
	{
		String useTable = chooseTable;
		String output = "";
		if (useTable.equalsIgnoreCase(""))
		{   
			for (int x = 0; x < this.tableListMaster.size(); x++)
			{
				if (!this.tableListMaster.get(x).getName().equalsIgnoreCase("~TMPCLP410631"))
				{
					useTable = this.tableListMaster.get(x).getName();
					System.out.println(this.tableListMaster.get(x).getName());
				} else {
					useTable = "Stammdat";					
				}
				
				output += "\nChecking both tables '" + useTable + "' for differences:\n-------------------------------------------------";
				System.out.println("\nChecking both tables '" + useTable + "' for differences:\n-------------------------------------------------");
				
				// Master
	            Statement stmtMaster = this.connectionMaster.createStatement();            
	            ResultSet rsMaster = stmtMaster.executeQuery( "SELECT * FROM " + useTable + " ORDER BY " + this.getPrimaryKey(useTable));
	            
	            while ( rsMaster.next() ) {
	                int numColumns = rsMaster.getMetaData().getColumnCount();
	               Tupel tup = new Tupel(useTable);
	                this.tupelListMaster.add(tup);
	                String key = this.getPrimaryKey(useTable);
	                
	                for ( int i = 1 ; i <= numColumns ; i++ ) {                   
	                	String value = "" + rsMaster.getObject(i);
	                	String name = rsMaster.getMetaData().getColumnName(i);
	                    tup.addColumn(name, value);
	                    
	                	if (rsMaster.getMetaData().getColumnName(i).equalsIgnoreCase(key))
	                		tup.setId(value);                   
	                }
	            }
	                                    
	            rsMaster.close();
	            stmtMaster.close();   
		
		//return this.compareLists(output);
		return output;
	}

Die Klasse Tupel sieht so aus (addColumn() erzeugt hier ein neues Attribut mit Wert)
Code:
import java.util.ArrayList;

public class Tupel {

	private String table = null;
	private String id = null;
	public ArrayList<Column> column;
	
	Tupel(String table)
	{
		this.table = table;
		this.column = new ArrayList<Column>();
	}
	
	public void addColumn(String name, String value)
	{
		Column col = new Column(name,value);
		this.column.add(col);		
	}

	public String getTable() {
		return table;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}
}

Und die Klasse Column sieht so aus
Code:
public class Column {
	
	private String name = null;
	private String value = null;
	
	Column(String name, String value)
	{
		this.name = name;
		this.value = value;
	}

	public String getName() {
		return name;
	}

	public String getValue() {
		return value;
	}
}

Die Fehlermeldung im speziellen:
Code:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOfRange(Unknown Source)
	at java.lang.String.<init>(Unknown Source)
	at java.nio.HeapCharBuffer.toString(Unknown Source)
	at java.nio.CharBuffer.toString(Unknown Source)
	at sun.jdbc.odbc.JdbcOdbcObject.BytesToChars(Unknown Source)
	at sun.jdbc.odbc.JdbcOdbc.SQLColAttributesString(Unknown Source)
	at sun.jdbc.odbc.JdbcOdbcResultSetMetaData.getColAttributeString(Unknown Source)
	at sun.jdbc.odbc.JdbcOdbcResultSetMetaData.getColumnName(Unknown Source)
	at DBCtrl.getDifferentEntries(DBCtrl.java:345)
	at UserInterface$5.widgetSelected(UserInterface.java:436)
	at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:215)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:938)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3490)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3104)
	at UserInterface.run(UserInterface.java:453)
	at java.lang.Thread.run(Unknown Source)
	at UserInterface.<init>(UserInterface.java:446)
	at Ctrl.main(Ctrl.java:40)

Gibt es eine Möglichkeit da Speicherplatz zu sparen bzw. wodurch wird denn diese Fehlermeldung überhaupt ausgelöst?

Lg,
goose
 
Hallo goose,

wie wärs mit Heapspace erhöhen?

java -Xmx256m MyApp

Die JVM verwendet standardmäßig maximal 64 MB. Diese kannst du je nach Bedarf und Möglichkeit nach obigem Muster erhöhen.


Vg Erdal
 
Die SQLException solltest du nicht werfen...denn wenn diese geworfen wird, kann das Statement und das Resultset nicht geschlossen werden....daher das ganze in ein try catch und das nochmal in ein finally....die Verbindung muss nehm ich mal an auch geschlossen werden...je nachdem muss du in dem finally nochmal ein try catch machen, damit es sicher geschlossen wird.

Und ob du wirklich einen Speicherfresser hasst kannst du mit der JConsole sehen. (enthalten in Java5/6)
 
Zuletzt bearbeitet:
Zusätzlich zu den anderen Anmerkungen: Da Du ja bereits die Anzahl der Spalten (numColumns) weißt, wenn Du ein Tupel anlegst, würd ich dieses auch an den Constructor mitgeben. Beim Erzeugen des ArrayLisr kannst Du so gleich die richtige finale Größe angeben. Dies sparrt spätere Realozierung.

Kommt der OutOfMem den gleich bei dem ersten Tupel?

Gruß
 
Zurück