2010-11-24 46 views
3

J'ai un programme qui doit allouer de l'espace de tas pour un très gros objet, mais je trouve que j'obtiens OutOfMemoryException s quand il semble y avoir beaucoup plus de tas libre que ce gros objet devrait exiger.Comment laisser PSOldGen se développer pour accueillir des objets très volumineux?

Ce programme de test illustre le problème:

public class HeapTest { 
    public static void main(String[] args) { 
    final int size = Integer.parseInt(args[0]); 
    System.out.println(size >> 20); 
    final byte[] buf = new byte[size]; 
    System.out.println(buf.length); 
    } 
} 

Si je cours comme java -Xmx40M -XX:+PrintGCDetails HeapTest 28000000, je reçois la sortie suivante:

26 
[GC [PSYoungGen: 317K->176K(9216K)] 317K->176K(36544K), 0.0007430 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC [PSYoungGen: 176K->144K(9216K)] 176K->144K(36544K), 0.0004650 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC [PSYoungGen: 144K->0K(9216K)] [PSOldGen: 0K->115K(9216K)] 144K->115K(18432K) [PSPermGen: 2710K->2710K(21248K)], 0.0053960 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC [PSYoungGen: 0K->0K(9216K)] 115K->115K(36544K), 0.0002010 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC [PSYoungGen: 0K->0K(9216K)] [PSOldGen: 115K->112K(15104K)] 115K->112K(24320K) [PSPermGen: 2710K->2708K(21248K)], 0.0078150 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
    at HeapTest.main(HeapTest.java:5) 
Heap 
PSYoungGen  total 9216K, used 476K [0x00000000ff2b0000, 0x0000000100000000, 0x0000000100000000) 
    eden space 7936K, 6% used [0x00000000ff2b0000,0x00000000ff327190,0x00000000ffa70000) 
    from space 1280K, 0% used [0x00000000ffa70000,0x00000000ffa70000,0x00000000ffbb0000) 
    to space 1280K, 0% used [0x00000000ffec0000,0x00000000ffec0000,0x0000000100000000) 
PSOldGen  total 27328K, used 112K [0x00000000fd800000, 0x00000000ff2b0000, 0x00000000ff2b0000) 
    object space 27328K, 0% used [0x00000000fd800000,0x00000000fd81c378,0x00000000ff2b0000) 
PSPermGen  total 21248K, used 2815K [0x00000000f3000000, 0x00000000f44c0000, 0x00000000fd800000) 
    object space 21248K, 13% used [0x00000000f3000000,0x00000000f32bff48,0x00000000f44c0000) 

Le tableau que je suis en train de créer devrait être d'environ 27344K , qui dépasse légèrement la taille de l'espace objet PSOldGen. Cependant, l'espace total inutilisé est d'environ 54000K, ce qui est presque deux fois ce qui est nécessaire pour mon tableau. Comme mon programme (réel) fonctionne sur le tableau in-situ, il n'utilise pratiquement pas de mémoire au-delà de ce qui est requis pour le tableau, alors allouer deux fois la mémoire dont j'ai besoin et en utiliser seulement la moitié me semble inutile.

Y a-t-il un moyen de convaincre la JVM de laisser l'ancienne génération se développer plus qu'elle ne le pourrait par défaut?

Répondre

3

Vous pouvez utiliser NewRatio, NewSize, MaxNewSize et SurvivorRatio pour régler la taille de la jeune génération , ainsi mise au point aussi, indirectement, la taille de ancienne génération.

En outre, si vous êtes préoccupé par génération permanente en utilisant trop de mémoire, vous pouvez régler cela avec MaxPermSize option de ligne de commande.

Voir Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine pour plus de détails, en particulier la partie sur generations.

Par exemple, la mise maximum jeune génération taille à 10M permet à votre exemple de programme à exécuter avec succès:

java -Xmx40M -XX:+PrintGCDetails -XX:MaxNewSize=10M HeapTest 28000000 

produit la sortie suivante sur ma machine:

26 
28000000 
Heap 
par new generation total 9216K, used 1499K [106810000, 107210000, 107210000) 
    eden space 8192K, 18% used [106810000, 106986ed0, 107010000) 
    from space 1024K, 0% used [107010000, 107010000, 107110000) 
    to space 1024K, 0% used [107110000, 107110000, 107210000) 
concurrent mark-sweep generation total 30720K, used 27343K [107210000, 109010000, 109010000) 
concurrent-mark-sweep perm gen total 21248K, used 4501K [109010000, 10a4d0000, 10e410000) 
+0

Etes-vous sûr qu'il est '-XX: NewSize' au lieu de' -XX: MaxNewSize' que je veux? Le premier est la limite inférieure, d'après ce que j'ai lu. – uckelman

+0

Non, je ne suis pas sûr - faites aussi vos propres recherches et tests, je vous indiquais juste dans la bonne direction. ;-) "NewSize" a fait fonctionner votre code sur ma machine, mais "MaxNewSize" semble plus logique pour vous, c'est vrai. –

+0

La raison pour laquelle j'ai demandé est que '-XX: NewSize' n'a pas fonctionné pour moi, mais' -XX: MaxNewSize' l'a fait. Est-ce que '-XX: MaxNewSize' fonctionne pour vous? J'espérais une solution qui fonctionne partout, puisque celle-ci sera déployée sur les machines de l'utilisateur. – uckelman