JNA/ByteBuffer, не будучи освобожденным и заставляя C "кучу" исчерпывать память

Структуры реализованы как типы значения, и классы являются ссылочными типами. Если у Вас будет переменная типа Foo, и Вы храните экземпляр Fubar в нем, он "Втиснет его" в ссылочный тип, таким образом побеждая преимущество использования структуры во-первых.

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

11
задан Mark Elliot 16 November 2009 в 20:28
поделиться

4 ответа

Я думаю, вы правильно диагностировали: у вас никогда не заканчивается куча Java, поэтому JVM не выполняет сборку мусора, а отображаемые буферы не освобождаются. Тот факт, что вы не Нет проблем при запуске GC вручную, кажется, это подтверждает. Вы также можете включить подробное ведение журнала сбора в качестве вторичного подтверждения.

Итак, что вы можете сделать? Что ж, первое, что я попробую, - это сохранить начальный размер кучи JVM небольшим, используя аргумент командной строки -Xms. Это может вызвать проблемы, если ваша программа постоянно выделяет небольшие объемы памяти в куче Java, поскольку она будет запускать сборщик мусора чаще.

Я бы также использовал инструмент pmap (или любой другой его эквивалент в Windows), чтобы изучить карту виртуальной памяти. Возможно, вы фрагментируете кучу C, выделяя буферы переменного размера. В этом случае вы увидите каждую большую виртуальную карту с промежутками между «анонимными» блоками. И решение здесь - выделить блоки постоянного размера, которые больше, чем вам нужно.

4
ответ дан 3 December 2019 в 08:04
поделиться

Я подозреваю, что ваша проблема связана с использованием прямых байтовых буферов. Их можно размещать вне кучи Java.

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

Чтобы изолировать проблему, я бы переключился на (Java ) буфер, выделенный кучей (просто используйте метод allocate вместо allocateDirect . Если это решит проблему с памятью, значит, вы нашли виновника. Следующий вопрос будет: прямой байтовый буфер имеет какое-либо преимущество с точки зрения производительности. Если нет (а я предполагаю, что нет), то вам не нужно беспокоиться о том, как его правильно очистить.

1
ответ дан 3 December 2019 в 08:04
поделиться

Фактически вы столкнулись с известной ошибкой в ​​Java VM . Лучший обходной путь, указанный в отчете об ошибке:

  • «Параметр -XX: MaxDirectMemorySize = может использоваться для ограничения объема используемой прямой памяти. Попытка выделить прямую память, которая может привести к превышению этого предела, вызывает полный Сборщик мусора, чтобы вызвать обработку ссылок и освобождение буферов, на которые нет ссылок ».

Другие возможные обходные пути включают:

  • Вставка случайных явных вызовов System.gc (), чтобы гарантировать, что прямые буферы будут освобождены.
  • Уменьшите размер молодое поколение, чтобы заставить собирать мусор чаще.
  • Явно объединяйте прямые буферы в пул на уровне приложения.

Если вы действительно хотите полагаться на прямые байтовые буферы, я бы предложил объединение на уровне приложения. В зависимости от сложности вашего приложения,

8
ответ дан 3 December 2019 в 08:04
поделиться

Если у вас заканчивается память кучи, автоматически запускается сборщик мусора. Однако, если у вас заканчивается прямая память, сборщик мусора не запускается (по крайней мере, на JVM Sun), и вы просто получаете OutOfMemoryError, даже если сборщик мусора освободит достаточно памяти. Я обнаружил, что в этой ситуации вам нужно запускать сборщик мусора вручную.

Лучшим решением может быть повторное использование одного и того же ByteBuffer, чтобы вам никогда не приходилось повторно размещать ByteBuffers.

1
ответ дан 3 December 2019 в 08:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: