Java Rätsel

Hallo,

okay, habs mit dem unter Ubuntu 64 Bit mit dem Open JDK 1.6.0_0 laufen lassen.

Damit das Problem auf jeden Fall auftritt reduzieren wir die Heap Size mal auf 48 MB. -Xmx48m

@limago:
Die Liste zu entfernen und nachträglich wieder hinzuzufügen ist keine zuverlässige Lösung... -> mit kleineren Heap Konfiguration gibt es trotzdem OOMEs. Ich bekomme auch mit 256 MB OOME's bei deiner Lösung.

@All
die Ursache für den OOME liegt in der Implementierung der Liste...
Vielleicht machen ja manche Methoden nicht ganz das was man von ihnen erwartet...

Gruß Tom
 
Das hier ist sicher nicht in Toms Sinn ;-) erfüllt aber alle Foderungen * grins *

package de.tutorials;


import java.util.List;

public class MemoryLeakExample {
public static void main(String[] args) {
List<List<?>> lists = new ArrayList<List<?>>();

for(int i = 0; i < 100;i++){
List<Integer> list = new ArrayList<Integer>();

for(int j = 0; j < 1000000;j++){
list.add(j);
}
lists.add(list);

System.out.println(i);
list.clear();
//?


}

System.out.println(lists);
}

static class ArrayList<T> extends java.util.ArrayList<T> {
public boolean add( T element) {
if (element instanceof List)
super.add(element);
return true;}
}
}
 
Hmm...

i = 100;

Ich denke richtig ist:
((ArrayList<Integer>)list).trimToSize( );
clear() setzt nur die Elemente im Array der ArrayList auf null und die Größe auf 0, aber behält die Größe des Arrays bei. Daher bleibt der Speicher auch reserviert.
 
Hat zwar nen bisschen gedauert bis ich drauf gekommen, aber wohl eher weil ich das Problem überschätzt habe. Hier meine Lösung:

Code:
import java.util.ArrayList;
import java.util.List;
 
public class MemoryLeakExample {
    public static void main(String[] args) {
        List<List<?>> lists = new ArrayList<List<?>>();
       
        for(int i = 0; i < 100;i++){
            List<Integer> list = new ArrayList<Integer>();
           
            for(int j = 0; j < 1000000;j++){
                list.add(j);
            }
            lists.add(list);
           
            System.out.println(i);
            list.clear();
            i = 100;
        }
       
        System.out.println(lists);
    }
}
 
Hallo,

die Schleifenvariablen zu manipulieren ist nicht wirklich eine Lösung... oder würdet ihr etwa so ein Speicherproblem in production code lösen? Durch verändern der Business Logic? In den meisten Fällen wird das wohl keine so gute Idee sein... ;-)

Gruß Tom
 
Habe die Liste die geleert wurde wieder auch von der array size gestaucht. Bei mir gehts mit 48MB heap(und weniger) auf Windows 7 & sun jre 6-17 auf x86_64 bit Maschine

package de.tutorials;

import java.util.ArrayList;
import java.util.List;

public class MemoryLeakExample {
public static void main(String[] args) {
List<List<?>> lists = new ArrayList<List<?>>();

for(int i = 0; i < 100;i++){
List<Integer> list = new ArrayList<Integer>();

for(int j = 0; j < 1000000;j++){
list.add(j);
}
lists.add(list);

System.out.println(i);
list.clear();
//+
ArrayList<?> ar = (ArrayList<?>) list;
ar.trimToSize();
//-
}

System.out.println(lists);
}
}
 
Hallo,

ein Aufruf von trimToSize() war natürlich des Rätsels Lösung.

Java:
package de.tutorials;

import java.util.ArrayList;
import java.util.List;

public class MemoryLeakExample {
    public static void main(String[] args) {
        List<List<?>> lists = new ArrayList<List<?>>();
        for(int i = 0; i < 100;i++){
            List<Integer> list = new ArrayList<Integer>();
            
            for(int j = 0; j < 1000000;j++){
                list.add(j);
            }
            lists.add(list);
            
            System.out.println(i);
            list.clear();
            ((ArrayList<?>)list).trimToSize();
        }
        System.out.println(lists);
    }
}

Das Beispiel sollte nochmal vor Augen führen, dass auch in Code der auf den ersten Blick sauber ausschaut üble Memory Leaks verborgen sein können die man nur durch genaue Kenntnisse der Implementierungsdetails der Java API auflösen kann.

Andere Collection Klassen wie HashMap, LinkedHashMap, ConcurrentHashMap etc. haben dieses Problem auch, bieten jedch keine Möglichkeit nachträglich die internen Strukturen (hier Hash-Buckets / Segments) zu stutzen.

TreeMap hat dieses Problem IMHO nicht. Dort wird beim clear() die Referenz auf den zugrundeliegenden RB-Tree (RedBlack) null gesetzt, so dass die internen Strukturen, soweit nicht mehr sonstwie referenziert, vom GC aufgesammelt werden können.

Java:
package de.tutorials;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;

public class MemoryLeakExample {
    public static void main(String[] args) {
        List<Map<?,?>> maps = new ArrayList<Map<?,?>>();
        for(int i = 0; i < 100;i++){
            Map<Integer, Integer> map = 
                new TreeMap<Integer, Integer>(); //Läuft durch
                //new HashMap<Integer, Integer>(); //OOME
                //new LinkedHashMap<Integer, Integer>(); //OOME
                //new ConcurrentHashMap<Integer, Integer>(); //OOME
            
            for(int j = 0; j < 100000;j++){
                map.put(j,j);
            }
            maps.add(map);
            
            System.out.println(i);
            map.clear();
            System.out.println(map);
        }
        System.out.println(maps);
    }
}

Gruß Tom
 
Hallo,

zum Jahres auftakt gibts dann mal ein neues (einfaches) Rätsel:

Gegeben:
Java:
package de.tutorials;

import java.util.LinkedHashMap;
import java.util.Map;

public class LRUMapExample {
    public static void main(String[] args) {
        int maxEntriesToKeep = 10;
        
        Map<Integer, Integer> lruMap = new LinkedHashMap<Integer, Integer>();

        for (int i = 0; i < 1000; i++) {
            lruMap.put(i, i);
        }

        System.out.println(lruMap);
    }
}

Wie macht man hier am einfachsten aus einer LinkedHashMap eine LRU Map (Last Recently Used) welche sich nur die letzten 10 hinzugefügten Elemente merkt?

Um dann folgende Ausgabe zu erzeugen:
Code:
{990=990, 991=991, 992=992, 993=993, 994=994, 995=995, 996=996, 997=997, 998=998, 999=999}
?

Viel Spaß und ein frohes neues Jahr allerseits :)

Gruß Tom
 
Nice...

import java.util.LinkedHashMap;
import java.util.Map;

public class LRUMapExample {

public static void main(String[] args) {
final int maxEntriesToKeep = 10;

Map<Integer, Integer> lruMap = new LinkedHashMap<Integer, Integer>( ) {
@Override
protected boolean removeEldestEntry(
java.util.Map.Entry<Integer, Integer> eldest) {
return this.size( ) > maxEntriesToKeep;
}
};

for (int i = 0; i < 1000; i++) {
lruMap.put(i, i);
}

System.out.println(lruMap);
}

}
 
Zurück