Как бороться с утечками памяти из внешней библиотеки

1

У меня есть небольшое java приложение, в котором запущен набор сложных вычислительных задач. Для обработки задач я использую внешнюю библиотеку, которая выполняет большую часть вычислений с помощью собственных методов и некоторого кода C К сожалению, после решения одной задачи библиотека страдает от сильных утечек памяти и поэтому может решить только одну задачу на выполнение приложения.

Проблема с памятью известна кодировщикам из библиотеки, но еще не исправлена и, возможно, никогда не будет (она имеет какое-то отношение к java garbage collector не работающему надлежащим образом с нативным inferface). Поскольку для этой конкретной библиотеки нет альтернативы, я ищу варианты для решения задач путем последовательного выполнения приложений.

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

Поскольку задачам часто нужны результаты предыдущих задач, это включает serializing и deserializing результатов выполнения в файлы. Для меня это не очень хорошая практика, потому что у пользователя практически нет возможности взаимодействовать с потоком управления программой.

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

Изменить дополнительную информацию:

  • Изменение корня проблемы: К сожалению, библиотека не является открытым исходным кодом, и у меня нет ни доступа к собственным методам, ни к java-интерфейсу api.

  • Новые процессы /JVMs: Это то же самое в этом контексте? У меня мало опыта работы с java-процессом api или запуском новых JVM. Мое предположение заключается в том, что это связано с запуском отдельной программы Java со своей main функцией с помощью ProcessBuilder.start()?

  • Обмен данными: это всего лишь пара kilobytes поэтому производительность не является проблемой. Тем не менее, решение без файлов было бы предпочтительнее, но если я правильно понимаю, что memory mapped files также используют локальные файлы. С другой стороны, разъемы звучат многообещающе.

  • 0
    Жаль, что у JVM нет эквивалента AppDomain (изолировать что?). В любом случае упомянутый подход - запуск отдельного процесса / JVM и использование IPC для передачи данных, звучит как «подходящий» взлом; Запрет на самом деле с использованием библиотеки, которая реализована наполовину правильно. (Но, может быть, есть некоторые методы, которые можно вызвать вручную, чтобы высвободить базовые ресурсы? Они должны быть задокументированы, если они существуют.)
  • 0
    Разве вы не можете позвонить напрямую во вспомогательную библиотеку C под JNI? Тогда у вас будет более точный контроль над памятью и вырежете сборщик мусора.
Теги:
memory-leaks

2 ответа

5

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

Решение, которое мы придумали, состояло в том, чтобы изолировать вызовы в библиотеку в собственном процессе. Этот процесс был ребенком мастер-процесса. Мастер-процесс содержит хороший код, а ребенок - плохой. Затем мы смогли отслеживать количество обращений к дочернему процессу и разорвать его, когда достигли определенного числа. Мы знали, что мы можем уйти с помощью X-призывов до того, как ребенок-процесс был поврежден.

Из-за характера нашей проблемы, воссоздание нового процесса позволило нам еще раз вызвать X-вызовы, прежде чем повторять.

Любое состояние было возвращено мастер-процессу при успешном вызове. Любое государство, собранное во время неудачного призыва, было отброшено, и мы снова начали.

Опять же, ни одно из вышеперечисленных "хорошо", но оно сработало для нас.

Для чего это стоит, если бы я сделал это снова, я использовал бы Akka и удаленных участников, которые сделали бы все подпроцессы, удаленные и т.д. Намного проще.

2

Это зависит. У вас есть исходный код этого внешнего приложения, т.е. можете ли вы его перекомпилировать? Самый простой подход - это, очевидно, исправить утечку в ее корне. Однако это может быть непрактичным. Если библиотека, как вы говорите, реализована с помощью собственных методов и некоторого кода на C, я не думаю, что проблема связана с сборщиком мусора Java, который не работает должным образом. Собственные методы и C-код обычно не хранят свои данные в куче JVM и поэтому не собираются мусором, т.е. Работа библиотеки очищается после себя.

Если утечка действительно находится в бит кода Java, который предоставляет библиотека, чем есть способ. Утечки памяти в Java происходят, забывая о ссылках, например, рассмотрим следующий пример:

class Foo {

  private ExpensiveObject eo; 

  Foo(ExpensiveObject eo) {
    this.eo = eo;
  }
}

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

void release(Foo foo) {
  Field f = Foo.class.getDeclaredField("eo");
  f.setAccessible(true);
  f.set(foo, null);
}

Однако это должно считаться последним курортом, поскольку это довольно хак.

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

Вы говорите, что в настоящее время вы используете файлы для связи между этими различными процессами. Зачем вам хранить данные в файле? Скорее рассмотрите использование сокетов или файлов с отображением памяти (NIO), если производительность важна для этого.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню