Подтвердить что ты не робот

JVM отправляет обратно память в ОС

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

Я хотел бы знать, как управлять тем фактом, что 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 ГБ с достаточной виртуальной памятью, конечно.

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

Спасибо за вашу помощь.

4b9b3361

Ответ 1

Чтобы управлять возвратом кучи в ОС, начиная с Java 5, используйте параметр -XX:MaxHeapFreeRatio, как описано в руководство по настройке.

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

Ответ 2

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

Во-вторых, вам нужно будет контролировать, что происходит с GC, используя

-verbosegc -XX:+PrintGCDetails 

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

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

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

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

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

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

Ответ 3

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