Дефрагментация сборки мусора Java - PullRequest
9 голосов
/ 29 сентября 2011

Я получаю исключение Java-кучи OutOfMemoryError, когда просто выделяю и освобождаю байтовый массив, даже если для выделения достаточно памяти. Ниже приведен краткий журнал. Из работы на другой JVM я знаю, что проблема связана с фрагментированной памятью и что самый большой свободный блок составляет всего около 6 МБ. Я думал, что Java (оракул) JVM должен заботиться о фрагментированной памяти.

Это мой тест:

  • Настройка Java JVM с параметрами -Xms10M -Xmx10M
  • Я выделяю байтовый массив, скажем, 90 процентов памяти JVM.
  • Установите для этого байтового массива значение null, а затем попытайтесь перераспределить байтовый массив на 90 процентов памяти JVM.
  • Из журналов видно, что память JVM полностью восстановлена, но мы не можем выделить такой же объем памяти.
  • Значит, память должна быть фрагментирована?

Вот мои данные:

Total Free Memory: 9881728  
Attempting to Allocate Array of size: 6917209  
Freeing Allocated Array of size: 6917209  
Total Free Memory: 9881728  
Attempting to Allocate Array of size: 6917209  
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

Другая JVM, которую я использую, - это CEE-J от Skelmir, я работаю на устройстве с низким объемом памяти, поэтому я не могу установить MaxPermSize. Интересно, что куча Java разделена на разные области. Могут ли эти области изменить размер после сборки мусора? Я провел другие тесты, где я, Сначала создайте байтовый массив для около 95 процентов памяти, затем освободите массив снова, затем я создаю массив массивов объектов, которые содержат хеш-карты, каждый с одной записью, Я очищаю массив и карты, затем снова перераспределяю те же массивы.

Я проверяю память каждый раз, когда выделяю и освобождаю. Сделав это, скажем 10 раз, я освобождаю память в последний раз, Затем я проверяю память, вижу, что у меня есть полное распределение JVM, Затем я снова пытаюсь выделить 95% от распределения JVM и вывести ту же JVM из исключения памяти, даже если он говорит, что у меня достаточно памяти для выделения?

public static void main(String[] args) throws InterruptedException {
        Runtime s_runtime = Runtime.getRuntime ();
        long used_memory = s_runtime.totalMemory () - s_runtime.freeMemory ();
        long start_memory = used_memory;
        long freeMemory = s_runtime.freeMemory();




        Integer numSubMemories = 1;
        Integer numMapEntries = 1;
        Integer numIterations = 1;
        float percentMem = (float) 1.0;
        if(args.length>0){
            if(args[0]!=null){
                String subEntries = args[0];
                if(subEntries.length()>0){
                    numSubMemories = Integer.parseInt(subEntries);
                }
            }
            if(args[1]!=null){
                String mapEntries = args[1];
                if(mapEntries.length()>0){
                    numMapEntries = Integer.parseInt(mapEntries);
                }
            }
            if(args[2]!=null){
                String numIts = args[2];
                if(numIts.length()>0){
                    numIterations = Integer.parseInt(numIts);
                }
            }
            if(args[3]!=null){
                String percentMemArg = args[3];
                if(percentMemArg.length()>0){
                    percentMem = Float.parseFloat(percentMemArg);
                }
            }
        }

        System.out.println("Total Free Memory: " + freeMemory);
        int numBytes = (int) (freeMemory * percentMem);
        System.out.println("Attempting to Allocate Array of size: " + numBytes);
        byte[] mbyteArray = new byte[numBytes];
        System.out.println("Freeing Allocated Array of size: " + numBytes);
        mbyteArray = null;



        TestMemory myMemory = new TestMemory(numSubMemories,numMapEntries);
        used_memory = s_runtime.totalMemory () - s_runtime.freeMemory ();
        System.out.println("Used Memory: " + used_memory);
        long after_allocation_memory = used_memory;
        for(int i=0;i<numIterations;i++){
            System.out.println("\t\t--Iteration: "+ i + " about to release Memory");
            myMemory.releaseMemoryArray(numSubMemories);

            System.out.println("\t\t--Iteration: "+ i + " about to reallocate Memory");
            myMemory.reAllocateMemoryArray(numSubMemories,numMapEntries);
            used_memory = s_runtime.totalMemory () - s_runtime.freeMemory ();
            System.out.println("\t\t--Used Memory: " + used_memory);
            System.out.println("\t\t--Max Memory: " + s_runtime.maxMemory());
            System.out.println("\t\t--Free Memory: " + s_runtime.freeMemory());
            System.gc();
            System.out.flush();
        }
        System.out.println("Releasing the Arrays for the last time");
         myMemory.releaseMemoryArray(numSubMemories);
         System.gc();
         freeMemory = s_runtime.freeMemory();
         //numBytes = (int)(freeMemory*0.95);
         System.out.println("Attempting to Allocate Array of size: " + numBytes);
         System.out.println("Total Free Memory: " + freeMemory);
         mbyteArray = new byte[numBytes];
        long end_memory = used_memory;
        //System.gc();
        Thread.sleep(6000);
        used_memory = s_runtime.totalMemory () - s_runtime.freeMemory ();

        System.out.println("------Results---------");
        System.out.println("        Start Memory: " + start_memory);
        System.out.println("        After Memory: " + after_allocation_memory);
        System.out.println("         End  Memory: " + end_memory);
        System.out.println("End Release   Memory: " + used_memory);

    }

Выходной журнал из второго теста. Всего свободной памяти: 9881728 Попытка выделить массив размером: 6917209 Выделение выделенного массива размера: 6917209 Используемая память: 7519744 -Выполнение: 0 собирается выпустить память -Выполнение: 0 собирается перераспределить память Используемая память: 7890928 Макс память: 10092544 Свободная память: 2147808 -Выполнение: 1 собирается выпустить память -Выполнение: 1 собирается перераспределить память Используемая память: 930952 Макс память: 10092544 Свободная память: 9107792 -Выполнение: 2 о выпуске памяти -Выполнение: 2 о перераспределении памяти Используемая память: 1181832 Макс память: 10092544 Память: 8856912 -Выполнение: 3 о выпуске памяти -Выполнение: 3 о перераспределении памяти Используемая память: 1190552 Макс память: 10092544 Память: 8848192 -Выполнение: 4 о выпуске памяти -Выполнение: 4 о перераспределении памяти Используемая память: 902408 Макс память: 10092544 Свободная память: 9190136 -Выполнение: 5 собирается выпустить память -Выполнение: 5 о перераспределении памяти Используемая память: 902408 Макс память: 10092544 Свободная память: 9190136 -Изменение: 6 собирается выпустить память -Выполнение: 6 о перераспределении памяти Используемая память: 902408 Макс память: 10092544 Свободная память: 9190136 -Изменение: 7 собирается выпустить память -Изменение: 7 о перераспределении памяти Используемая память: 902408 Макс память: 10092544 Свободная память: 9190136 -Выполнение: 8 собирается выпустить память -Выполнение: 8 о перераспределении памяти Используемая память: 902408 Макс память: 10092544 Свободная память: 9190136 -Изменение: 9 собирается выпустить память -Выполнение: 9 о перераспределении памяти Используемая память: 902408 Макс память: 10092544 Свободная память: 9190136 Выпуск Массивов в последний раз Попытка выделить массив размером: 6917209 Всего свободной памяти: 9956688 Исключение в потоке "main" java.lang.OutOfMemoryError: пространство кучи Java

Ответы [ 3 ]

3 голосов
/ 29 сентября 2011

Куча Java разбита на несколько областей.Одно распределение не может охватывать области.В Oracle JRE есть различные -XX опции [я позволю кому-то еще указать на детали], которые позволяют конфигурировать распределения.Вы могли бы установить области eden и оставшийся в живых, чтобы быть очень маленькими.Еще одна проблема, если после сбора недостаточно памяти, вы все равно можете получить OOME, чтобы предотвратить побои (опять же -XX опции для управления этим).

1 голос
/ 29 сентября 2011

Добавьте аргумент -XX: MaxPermSize, чтобы обеспечить достаточное пространство для кучи.

-XX:MaxPermSize=512m
0 голосов
/ 29 сентября 2011

В какой другой JVM вы успешно запустили свою программу. Если вы говорите о IBM jdk, то здесь управление кучей полностью отличается от управления кучей jvm от Sun (Oracle). http://download.boulder.ibm.com/ibmdl/pub/software/dw/jdk/diagnosis/GCandMemory-042005.pdf

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...