2015-12-29 2 views
1

Простая программа, выделяющая 1 многомерный массив, вызывает непрерывные GC (все сборщики мусора), если куча достаточно велика, чтобы создать внешний массив. Похоже, что GC пытается многократно. С сборкой продукта и кучей 6G выделение занимает 3 минуты.Многомерный массив в явном неактивном распределении памяти

С быстрой сборкой отладки выделение занимает более 20 минут.

Выделение 1-мерного массива, который занимает одну и ту же память, быстро и не выбрасывает исключение из памяти Почему?

public class Test { 
    public static void main(String[] args) { 
      int a1 = 1; 
      long maxMemory = Runtime.getRuntime().maxMemory(); 
      int s = (int) (Math.sqrt(Math.sqrt((double) maxMemory))); 
      System.out.println("s: " + s); 
      int[][][][] a2; 
    try { 
     a2 = new int [s][s][s][s]; 
     a2 [s-1][s-1][s-1][s-1] = a1; 
     if (a2 [s-1][s-1][s-1][s-1] != 1) { 
      throw new RuntimeException("Error: " + a2 [s-1][s-1][s-1][s-1]); 
     } 
    } catch (OutOfMemoryError e) { 
      System.out.println("Passed."); 
    } 
    } 
} 

ответ

2

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

Runtime rt = Runtime.getRuntime(); 
long availableMemory = rt.maxMemory() - (rt.totalMemory() - rt.freeMemory()); 

Вторая проблема заключается в том, что вы пытаетесь создать столько int значения, максимальный размер кучи в байтах. Поскольку int представлен 4 байтами, вы пытаетесь выделить в 4 раза больше памяти, чем максимальный размер кучи, это всегда должно вызывать OOME. Таким образом, размер s должен быть пересчитаны как:

int s = (int) (Math.sqrt(Math.sqrt((double) availableMemory)))/4; 

Наконец, вы не просто выделить Int значения, но и ссылки на int[], int[][] и int[][][], согласно многомерности вашего массива. Поэтому фактический максимальный размер массива должен быть скорректирован для распределения этих ссылок. Если я не ошибаюсь, это эквивалентно решению (или найти хорошее приближение) это уравнение:

availableMem >= s * refSize + s^2 *refSize + s^3 * refSize + s^4 * 4 

, где refSize является размер представления ссылки в JVM, которая может зависеть от платформу (например, 4 байта для 32-разрядной JVM, 8 байтов для 64 бит).

+0

Спасибо за указатель @Lolo –

Смежные вопросы