2009-03-23 4 views
18

У меня есть вопрос относительно управления памятью JVM (по крайней мере, для SUN).JVM отправка обратно памяти в ОС

Я хотел бы знать, как управлять тем фактом, что JVM отправляет неиспользованную память обратно в ОС (окна в моем случае).

Я написал простую программу java, чтобы проиллюстрировать, что я ожидаю. Запустите его с параметром -Dcom.sun.management.jmxremote, чтобы вы могли также контролировать кучу с помощью jconsole.

со следующей программой:

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<byte[]> usedMemory = new LinkedList<byte[]>(); 
    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) {} 
    } 
} 

Внутренняя куча свободна после того, как первый GC делается (что, как ожидается), но память отсылаются только в ОС, начиная с третьего GC. После четвертого, полная выделенная память отправляется обратно в ОС.

Как настроить JVM для управления этим поведением? На самом деле, моя проблема в том, что мне нужно запустить несколько сеансов клиентов CITRIX на сервере, но я хотел бы, чтобы запущенные JVM на сервере освобождали память как можно скорее (у меня в моем приложении только несколько функций с высокой потребляемой памятью) ,

Если это поведение невозможно контролировать, могу ли я позволить ему это сделать и увеличить вместо этого виртуальную память ОС и позволить ОС использовать ее по своему усмотрению без больших проблем с производительностью. Например, возникли бы проблемы с 10 java-процессами с памятью 1 ГБ (с реальными выделенными объектами размером 100 МБ в куче) на сервере с 4 ГБ с достаточной виртуальной памятью.

Я думаю, что другие люди уже столкнулись с такими вопросами/проблемами.

Благодарим за помощь.

+0

wow теги полностью съедали ваш код –

+0

Я немного переформатировал фрагмент кода, чтобы использовать возможности подсветки синтаксиса Stackoverflow. Надеюсь, вы не против –

+0

Спасибо, мне не удалось правильно отобразить его. Я не разочарован, я только недавно здесь ;-) –

ответ

15

Для управления возвратом кучи в ОС, начиная с Java 5, используйте опцию -XX:MaxHeapFreeRatio, как описано в разделе tuning guide.

Если вы чувствуете, что ваш вопрос существенно отличается от this one, пожалуйста, укажите, как.

+0

Спасибо за ваш ответ, я сделаю некоторые тесты с этими подсказками. –

+0

Кажется, что часть его вопроса: «Безопасно ли вы объединять память машины, если у вас есть виртуальная память, чтобы вернуться», что отличается от связанного вопроса. – Kai

7

Прежде всего, System.gc() также может ничего не делать. Вы действительно не можете полагаться на это, чтобы сделать сборку мусора так, как вы предлагаете.

Во-вторых, вы хотите, чтобы контролировать то, что на самом деле происходит на с GC с помощью

-verbosegc -XX:+PrintGCDetails 

в вашем вызове Java. Или с помощью JConsole, который звучит так, как будто вы делаете. Но в System.gc() меня испугало, что вы считаете, что ошибаетесь ...

Я подозреваю, что когда вы говорите, что вторая или третья сборка мусора - это когда она освобождает память, вы просто ошибаетесь сбор мусора. Запрос GC не GC! Поэтому проверьте журналы (interpret them this way), распечатанные PrintGCDetails.

На самом деле моя проблема заключается в том, что мне нужно запустить несколько CITRIX клиентов сеансов на сервере, но я хотел бы бегущих JVMs на сервере, чтобы освободить память как можно скорее (у меня есть только несколько высокое потребление памяти функции в моем приложении).

Несмотря на то, что ваша проблема верна, решение, которое вы собираетесь использовать, немного теневое. Именно по этой причине JVM нуждается в размере кучи, чтобы гарантировать, что это пространство будет запущено. Похоже, вы склоняетесь к запуску приложения, а затем ожидаете, что JVM изменит свою кучу, а затем запустит еще один такой что вы перегружаете ресурсы на машине. Не делайте этого, потому что все это взорвется, как только приложение займет больше памяти, чем вы предполагали, но которое оно имеет право.

Я полностью верю, что вы не хотите быть микро управляющим кучей Java таким образом.

Достаточно читайте http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html, чтобы понять поколение и какие компромиссы большей или меньшей кучи.

+0

Это не касается вопроса, связанного с обменом памятью между ОС и JVM, а не внутри самой JVM. – erickson

+0

@erickson - Вы правы, удалите внутренние кучи JVM. Мне показалось, что он задавал слишком большую кучу, и не нужно было так выделять ее меньше. Однако, похоже, это не так. – Kai

0

Я бы не стал беспокоиться об этом, пока не увидим измеримые замедления. Если у процесса есть выделенная память, которую он не использует, ОС по необходимости заменяет неиспользованные куски на диск.

+2

Итак, ваше предложение состоит в том, чтобы выделить как минимум столько виртуальной памяти, сколько количество процессов, которые я умножаю, на разрешенный размер кучи JVM для каждого процесса. Например, 10 процессов с максимальной кучей 1GO, тогда мне нужно плюс/минус 10 ГБ виртуальной памяти? –

+0

Давай поменяем ... какая отличная идея, чтобы полностью убить выступления. – LtWorf