JVM rimanda la memoria al sistema operativo

Ho una domanda riguardante la gestione della memoria JVM (almeno per quella del SUN).

Mi piacerebbe sapere come controllare il fatto che la JVM rimandi la memoria inutilizzata al sistema operativo (Windows nel mio caso).

Ho scritto un semplice programma java per illustrare ciò che mi aspetto. Eseguirlo con l’opzione -Dcom.sun.management.jmxremote in modo che sia ansible monitorare l’heap con jconsole, ad esempio.

Con il seguente programma:

package fr.brouillard.jvm; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.LinkedList; import java.util.List; public class MemoryFree { private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); private List usedMemory = new LinkedList(); private int totalMB = 0; private int gcTimes = 0; public void allocate(int howManyMB) { usedMemory.add(new byte[howManyMB * 1024 * 1024]); totalMB += howManyMB; System.out.println(howManyMB + "MB allocated, total allocated: " + totalMB + "MB"); } public void free() { usedMemory.clear(); } public void gc() { System.gc(); System.out.println("GC " + (++gcTimes) + " times" ); } public void waitAnswer(String msg) { System.out.println("Press [enter]" + ((msg==null)?"":msg)); try { reader.readLine(); } catch (IOException e) { } } public static void main(String[] args) { MemoryFree mf = new MemoryFree(); mf.waitAnswer(" to allocate memory"); mf.allocate(20); mf.allocate(10); mf.allocate(15); mf.waitAnswer(" to free memory"); mf.free(); mf.waitAnswer(" to GC"); mf.gc(); mf.waitAnswer(" to GC"); mf.gc(); mf.waitAnswer(" to GC"); mf.gc(); mf.waitAnswer(" to GC"); mf.gc(); mf.waitAnswer(" to exit the program"); try { mf.reader.close(); } catch (IOException e) {} } } 

L’heap interno è gratuito una volta eseguito il primo GC (cosa previsto) ma la memoria viene inviata al sistema operativo solo a partire dal terzo GC. Dopo il quarto, la memoria allocata completa viene inviata al sistema operativo.

Come configurare la JVM per controllare questo comportamento? In realtà il mio problema è che ho bisogno di eseguire diverse sessioni di client CITRIX su un server, ma vorrei che le JVM in esecuzione sul server liberassero la memoria il prima ansible (ho solo poche funzioni di memoria ad alto consumo nella mia applicazione).

Se questo comportamento non può essere controllato, posso lasciarlo così e aumentare invece la memoria virtuale del SO e lasciare che il SO lo usi come vuole senza grossi problemi di prestazioni. Ad esempio, ci sarebbero problemi ad avere 10 processi java di 1GB di memoria (con solo 100MB di oggetti allocati reali nell’heap) su un server da 4 GB con una memoria virtuale sufficiente, naturalmente.

Immagino che altre persone abbiano già affrontato tali domande / problemi.

Grazie per l’aiuto.

Per controllare il ritorno dell’heap sul sistema operativo, da Java 5 in poi, utilizzare l’opzione -XX:MaxHeapFreeRatio , come descritto nella guida alla regolazione .

Se ritieni che la tua domanda sia significativamente diversa da questa , ti preghiamo di indicare come.

Innanzitutto, System.gc () potrebbe anche non fare nulla. Non puoi davvero fare affidamento su di esso per fare una garbage collection nel modo che stai suggerendo.

In secondo luogo, dovrai monitorare ciò che sta effettivamente accadendo con GC usando

 -verbosegc -XX:+PrintGCDetails 

nella tua invocazione di java. O usando JConsole, che sembra che tu stia facendo. Ma System.gc () mi fa paura che tu stia contando la cosa sbagliata …

Sospetto che quando dici che il secondo o il terzo garbage collection è quando libera la memoria, stai semplicemente incontrando le raccolte di dati inutili. Una richiesta di GC non è un GC! Quindi controlla i log ( interpretali in questo modo ) che PrintGCDetails stampa.

In realtà il mio problema è che ho bisogno di eseguire diverse sessioni di client CITRIX su un server, ma vorrei che le JVM in esecuzione sul server liberassero la memoria il prima ansible (ho solo poche funzioni di memoria ad alto consumo nella mia applicazione).

Mentre il tuo problema è valido, la soluzione che stai cercando è un po ‘losca. La JVM ha bisogno di una dimensione heap esattamente per questo motivo – in modo che possa essere garantito questo spazio per l’esecuzione. Sembra che tu ti stia appoggiando all’avvio di un’app, quindi attendi che la JVM ridimensiona il suo heap, quindi avvia un’altra che stai prenotando in overbooking le risorse sulla macchina. Non farlo, perché esploderà una volta che un’app sta prendendo più memoria di quanto pensavi, ma a cui ha diritto.

Sono pienamente convinto che tu non voglia essere micro gestendo l’heap di Java in questo modo.

Leggi abbastanza di http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html per capire le generazioni e quali sono i compromessi di un heap più grande / più piccolo.

Non mi preoccuperei finché non vedrai rallentamenti misurabili. Se un processo ha una memoria allocata che non sta usando, il SO scambierà i pezzi non utilizzati sul disco, se necessario.