Проблема с Runtime.freeMemory () - Java - PullRequest
3 голосов
/ 23 сентября 2010

Эй, я тестирую Runtime.freeMemory () с этим кодом:

 Runtime runtime = Runtime.getRuntime();
 long freeMemory = runtime.freeMemory();

 // This is some arbitary factor that should work <= 1
 double factor = 0.8;

 int size = (int) (factor * freeMemory);
 byte[] testArray = new byte[size];

Я создаю байтовый массив размером, близким к значению freeMemory.По какой-то причине, особенно когда я ограничиваю память программы до 8 МБ, код выдает исключение OutOfMemory для любого фактора> 0,55.Это действительно не имеет смысла, конечно, freeMemory означает freeMemory, я ожидаю, что это будет немного, но не вдвое больше, чем на самом деле бесплатно.

Есть предложения о том, что происходит?Спасибо

(обратите внимание, что в моих тестах я ограничил объем памяти, доступной программе, до 8 МБ или 16 МБ, используя -Xmx8M и т. Д.)

Ответы [ 5 ]

2 голосов
/ 23 сентября 2010

На самом деле ваша свободная память делится на два поколения: http://java.sun.com/docs/hotspot/gc1.4.2/ одно - это "молодое" поколение, а другое - "наемное" поколение.Если вы запускаете с параметром -verbose: gc -XX: + PrintGCDetails VM, вы можете увидеть, сколько занимает каждое поколение.Я узнал, что могу полностью заполнить свое штатное поколение, но не более того.

0 голосов
/ 23 сентября 2010

Этот ответ основан на комментарии Губки, в основном вопросе.

Если вместо того, чтобы пытаться создать массив в одном патроне, вы разбили его создание на множество меньших массивов, вы можете заполнить свободную память с коэффициентом около 0,98.

     Runtime runtime = Runtime.getRuntime();
     long freeMemory = runtime.freeMemory();

     // This is some arbitary factor that should work <= 1
     double factor = 0.8;

     int size = (int) (factor * freeMemory);


     int slice = 100;
     byte[][] testArrays = new byte[slice][1];
     for (int i = 1; i <= slice; i++) {
            testArrays[i-1] = new byte[size / slice];
            System.out.println("Allocated: " + i * size / slice);
     }

     System.out.println("Created! "+testArrays.length);
0 голосов
/ 23 сентября 2010

Я думаю, что это связано с размерами разделов кучи.Когда JVM запускается, он собирается разделить доступную память кучи на несколько «пробелов»;например, есть пространство для вновь созданных объектов, пространство для постоянных объектов, пространство «eden» для объектов, которые пережили первый цикл GC, и так далее.Фактические размеры пространств настраиваются (с помощью параметров JVM), но есть вероятность, что пространство «новых объектов» значительно меньше 8 МБ.

При попытке выделить массив, содержащий 55% отСообщив о свободной памяти, диспетчер памяти должен найти этот объем непрерывной памяти в пространстве «новых объектов».Если вы получаете OOME, то это потому, что фактическое разбиение таково, что необходимый объем непрерывной памяти недоступен ... даже после запуска GC.пытаемся запустить JVM со слишком маленькой кучей для того, что вы пытаетесь сделать.Как правило, плохо относиться к размеру кучи Java.Ваше приложение будет работать быстрее (и с меньшими проблемами), если вы выделите ему много памяти.

0 голосов
/ 23 сентября 2010

Лучший способ получить контроль над этим состоял бы в том, чтобы запустить ваш код через профилировщик, который способен показать вам, как распределяется память в вашей системе с течением времени.Если вы используете Eclipse, убедитесь, что у вас установлен TPTP, я уверен, что другие большие IDE где-то имеют такую ​​же функцию.

0 голосов
/ 23 сентября 2010

Попробуйте собрать мусор перед созданием тестового массива с помощью runtime.gc().

Если вы не создаете совершенно новую JVM каждый раз, вы можете получить бит, имея разные начальные состояния.


Шахта работает для значений> 1. 1,25, например.Затем я получаю исключение «пространства кучи».


Здесь, возможно, вы хотите вместо этого использовать maxMemory ().

public class Mem2 {
    public static void main(String[] args) {


        Runtime runtime = Runtime.getRuntime();
        runtime.gc();

        long freeMemory = runtime.freeMemory();

        // This is some arbitary factor that should work <= 1
        double factor = 1.29;

        int size = (int) (factor * freeMemory);
        System.out.println("      freememory is " + freeMemory);
        System.out.println("            size is " + size);
        System.out.println("the total memory is " + runtime.totalMemory());
        System.out.println("  the max memory is " + runtime.maxMemory());
        byte[] testArray = new byte[size];
    }
}

Вывод:

      freememory is 84466864
            size is 108962254
the total memory is 85000192
  the max memory is 129957888

Process finished with exit code 0

Так что, похоже, около 20M я не могу учесть.

Я думаю, что totalMemory () - это объем памяти, выделенный в данный момент JVM, freeMemory () - это то, сколько из этого было использовано, иmaxMemory () - это жесткое ограничение.


Вы можете увидеть взаимодействие между totalMemory() и freememory() с этим вариантом в вашем коде.

public class Mem3 {

    public static void main(String[] args) {


        Runtime runtime = Runtime.getRuntime();

        for (int i = 0; true; i++) {
            runtime.gc();
            int size = i * 10000000;
            System.out.println("                 i is " + i);
            System.out.println("              size is " + size);
            System.out.println("b       freememory is " + runtime.freeMemory());
            System.out.println("b the total memory is " + runtime.totalMemory());
            System.out.println("b   the max memory is " + runtime.maxMemory());
            byte[] testArray = new byte[size];
            System.out.println("                array " + testArray.length);
            System.out.println("a       freememory is " + runtime.freeMemory());
            System.out.println("a the total memory is " + runtime.totalMemory());
            System.out.println("a   the max memory is " + runtime.maxMemory());
            System.out.println(" ");
        }

    }
}

Если вы запустите этои посмотрите на значения до и после, вы можете увидеть, что происходит.Обратите внимание на то, что происходит между целыми числами 6 и 7:

                 i is 6
              size is 60000000
b       freememory is 84300496
b the total memory is 85000192
b   the max memory is 129957888
                array 60000000
a       freememory is 24300472
a the total memory is 85000192
a   the max memory is 129957888

                 i is 7
              size is 70000000
b       freememory is 84300496
b the total memory is 85000192
b   the max memory is 129957888
                array 70000000
a       freememory is 59258168
a the total memory is 129957888
a   the max memory is 129957888

Мы видим в 6, что после выделения 60 миллионов осталось около 24 миллионов.В 7, однако, мы превысили порог.Выделено больше памяти (обратите внимание на totalMemory), а freeMemory теперь чуть менее 60M.

...