Есть ли способ заставить JVM использовать своп независимо от того, насколько велика потребность в памяти?

Вот моя ситуация: у меня есть задача, требующая большого количества памяти. У меня недостаточно бара, и независимо от того, что я пробовал (Jrockit с/3gb-переключателем и т.д.), Я не могу предоставить JVM достаточное количество бара, и операция прекращается с исключением, говоря мне, что мне нужно больше места для кучи.

Можно ли каким-либо образом заставить JVM использовать механизм обмена ОС, чтобы он не исчерпал память? Это 32-разрядная версия Windows xp

Это займет много времени, но мне все равно, мне просто нужно, чтобы эта операция была завершена.

У меня закончились опции, и я не могу контролировать ни одну из переменных здесь.

Это требуемое редактирование, так как я получаю тот же ответ от почти всех:) Это не мой код. Кто-то написал инструмент, который читает xml файл в репозиторий. Инструмент использует EMF и загружает всю модель сразу. Все, что я могу сделать, это передать XML файл. В случае нативного кода, работающего под Windows или Linux и т.д., ОС предоставляет ему память, используя пространство виртуальной памяти/подкачки, и приложение не знает об этом. Мне было интересно, можно ли сделать то же самое с JVM. В Windows 32 бит, -Xmx может доходить до определенной суммы, но этого недостаточно. Выйти и покупать новое оборудование для меня сейчас не вариант. Поэтому мне было интересно, возможно ли, что JVM работает как собственные процессы. Медленно, но все еще работает. Видимо, это невозможно, и мне не повезло. Мне просто нужно знать, действительно ли у меня нет вариантов.

Ответ 1

По-видимому, есть один путь в пределах кучи Java. Он даже используется в коммерческом продукте под названием BigMemory, который в основном позволяет вам иметь почти неограниченную память путем прозрачной замены ОС на swap и/или на диск при необходимости.

Идея заключается в использовании прямого ByteBuffer для хранения данных ваших объектов. Поскольку содержимое буферов прямого байта хранится в собственной памяти процесса (в отличие от кучи), вы можете полагаться на механизм свопинга ОС для замены памяти для вас. Я нашел это на этом веб-сайте (поиск "прямого байтового буфера" на странице).

Вот как вы можете реализовать его (java-псевдо-code'ish):

class NativeMemoryCache{
  private Map<Object, ByteBuffer> data = new HashMap<...>();

  public void put(Object key, Serializable object){
    byte[] bytes = serialize(object);
    //allocate native memory to store our object
    ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
    buf.put(bytes);
    buf.flip();
    data.put(key, buf);
  }

  public Object get(Object key){
    ByteBuffer buf = data.get(key).duplicate();
    byte[] bytes = new byte[buf.remaining()];
    buf.get(bytes);
    return deserialize(bytes);
  }

  private byte[] serialize(Object obj){ ... }
  private Object deserialize(byte[] bytes){ ... }
}

Надеюсь, вы получите эту идею. Вам просто нужно реализовать сериализацию (вы также можете сжать объекты с помощью zip.Это будет эффективно, если у вас мало крупных объектов, в частности, содержащих zippable данные, такие как строки).

Конечно, объект NativeMemoryCache, хэш-карта data и key будет в куче, но это не должно занимать много памяти.

Ответ 2

Как указано в других ответах, вы используете переключатель -Xmx, чтобы предоставить больше ОЗУ для JVM.

Однако существует ли ограничение на то, насколько высок вы. В 32-битной системе это, вероятно, будет 2GiB, может быть, 3 или 4 GiB, если JVM поддерживает его. Для Sun JVM предел составляет 1500 Мбайт на 32-битной Windows, согласно Java -Xmx, максимальная память в системе.

По фундаментальным архитектурным причинам процесс не может (без специальных методов) получать более 4 Гбайт памяти (включая любое пространство подкачки, которое он может использовать), поэтому существует ограничение на значения -Xmx.

Если вы пробовали максимально возможное значение и все еще получаете ошибки OOM, тогда ваши единственные варианты:

  • исправить приложение, чтобы он меньше RAM

или

  • переместите его на 64-битную ОС и увеличьте -Xmx еще дальше

Edit:

Обратите внимание, что ограничение 4 GiB является ограничением архитектуры процессора, поэтому оно применимо к любому процессу, Java или нет. Поэтому даже трюки с размещением на местах вам не помогут. Единственный способ - использовать более одного процесса, но для этого потребуется фундаментальная переработка приложения, что, вероятно, будет столь же сложным, как просто исправление приложения, чтобы использовать меньше оперативной памяти. Таким образом, два варианта выше - ваши единственные (разумные) варианты.

Изменить 2:

Чтобы ответить на новую часть вашего вопроса:

Мне было интересно, возможно ли заставить JVM работать как родной процессы.

Это недоразумение. JVM работает как родной процесс в этом отношении: куча, которую он использует, находится в памяти, выделенной из ОС JVM; для ОС это просто выделенная память, и ОС поменяет ее, как и любую другую память, если она будет похожа на нее - в этом нет ничего особенного.

Причина, по которой куча не может расти бесконечно, заключается не в том, что она не может быть больше физической ОЗУ (я могу попробовать, по крайней мере, на Linux/x86), но каждый процесс ОС (который есть JVM) не может получить более 4 ГБ оперативной памяти. Таким образом, на 32-битных системах вы никогда не можете иметь кучу более 4 гигабайт. На практике это может быть намного меньше, потому что память кучи не должна быть фрагментирована (см., Например, максимальная память Java в Windows XP), но 4GiB - это жесткий, неизбежный предел.

Ответ 3

Согласно моему опыту, JVM запрашивает память из ОС, которая может выделять ее либо в ОЗУ при свопинге. Это зависит от того, сколько у вас ресурсов. Память, которую вы можете выделить в java, зависит не от вашей оперативной памяти, а от опции командной строки -Xmx, которую вы указываете при запуске вашей JVM. Если, например, недостаточно памяти в ОЗУ, JVM получает его из swap и (я считаю) даже не знаю об этом.

Кстати, вам действительно не нужно столько памяти. Я согласен с парнями, которые это сказали. Я предлагаю вам ознакомиться с вашим дизайном.

Ответ 4

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

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

Это либо время, чтобы получить больше памяти, что в наши дни относительно дешево. или уменьшить потребность в памяти. Использование swap будет просто завершаться навсегда.

BTW: вы можете купить сервер на 24 ГБ для примерно 1800 и 64 ГБ серверов на сумму около 4200 фунтов стерлингов. За £ 53 000 вы можете получить сервер с 1 Тб памяти!: D