Что происходит с распределением памяти здесь? - PullRequest
1 голос
/ 30 апреля 2009

Пытаясь определить максимальный размер массива Java String на моей машине, я столкнулся с некоторыми интересными результатами, вот код,

   String [] max;
   int i = 15444000;
   while(true){
      try{
         max = new String[i];
         System.gc();
         Thread.sleep(10);
      }catch(InterruptedException e){}
   i += 1;
   System.out.println(i);
   }

Всякий раз, когда я запускаю этот код, вывод выводит его 15444038 перед выдачей OutOfMemoryError. Это заставляет меня думать, что максимальный размер массива Java String на моей машине равен 15444038 , однако, если я заменю

int i = 15444000;

с

int i = 15444037; // or any i between 15444037 and 15444002

OutOfMemoryError происходит мгновенно. Почему это так, и каков истинный максимальный размер массива Java String на моем компьютере?

Ответы [ 5 ]

2 голосов
/ 30 апреля 2009

Максимальный размер массива, который вы сможете выделить, зависит от того, насколько велика максимальная память для виртуальной машины. Вы можете изменить максимум с помощью аргумента командной строки -Xmx .

Также http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html#gc() состояний

Вызов метода gc предполагает, что виртуальная машина Java затрачивает усилия на утилизацию неиспользуемых объектов, чтобы сделать доступной память, которую они занимают, для быстрого повторного использования. Когда управление возвращается из вызова метода, виртуальная машина Java сделала все возможное, чтобы освободить пространство от всех отброшенных объектов.

Таким образом, ваше расхождение может быть связано с тем, что сборщик мусора не очищал каждый раз по-разному ( Виртуальная машина Java приложила максимум усилий для освобождения пространства ).

1 голос
/ 30 апреля 2009

Я думаю, что может происходить, и это всего лишь предположение, может ли JIT (компилятор Just in time) оптимизировать часть памяти? Второе предположение - сборщик мусора освобождает немного памяти перед повторным запуском цикла. Попробуйте добавить сборщик мусора, прежде чем выделять массив.

0 голосов
/ 30 апреля 2009

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

Еще одна вещь, которую стоит знать: вызов System.gc () не означает, что сборщик мусора работает. Это всего лишь предложение.

0 голосов
/ 30 апреля 2009

Когда вы работаете с небольшим размером, сборщик мусора может собирать память из поколения молодой / Иден / выживший и перемещать ее в поколение с постоянным сроком службы. Выделение для больших массивов производится в штатном поколении. Поскольку GC ранее перемещал объекты в арендованную область, теперь он имеет меньшую вместимость.

Возможно. Это все зависит от реализации и сроков. Такое большое распределение, вероятно, лучше всего выполнять через прямые распределенные буферы NIO.

0 голосов
/ 30 апреля 2009

Ну, вы могли бы спорить о многих вещах, но я думаю, что правильный ответ - "кого это волнует?" Ответ на ваш вопрос о том, что максимум с вашей конфигурацией, составляет «около 15 миллионов». Если вы действительно хотите беспокоиться о выделении кучи до последних 4 байтов, запрограммируйте на ассемблере ...

P.S. Вещи, которые могли бы происходить, включают объекты, используемые на ранних этапах в потоке обслуживания, который становится сборщиком мусора, когда программа немного запускается. Потенциально возможен еще один феномен JIT-оптимизации, на который намекал другой автор: есть некоторые потоки, которые начинают выделять небольшие объекты в куче, а затем в какой-то момент оптимизируются JIT для «распределения» их в регистрах / стеке. Но, честно говоря, если вы не обнаружите, что размер массива, который вы можете выделить, внезапно уменьшится вдвое, я бы на самом деле не слишком беспокоился об этом.

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