Рубрики
Без рубрики

Утечка памяти Java для JDBC

Контекст, в котором я написал движок, используя пользовательский загрузчик классов. Для этого просто создайте n… С тегами java, jdbc, утечка памяти, сборщик мусора.

Я написал движок, используя пользовательский загрузчик классов. Для этого просто создайте новый URLClassLoader , загрузите jar и выполните нужный код, затем закройте URLClassLoader. Если новый загрузчик классов не имеет доступа к текущему загрузчику классов, загруженные классы не имеют доступа к вашему коду. Хорошо! Очень Хорошо!

URL[] jars = new URL[] { /* The jars to be loaded */ }; //
try (URLClassLoader classLoader = new URLClassLoader(jars)) {
    Job job = classLoader.loadClass(Job.class.getName());
    job.execute();
}

Но… У нас нет контроля над кодом, загруженным из внешней банки. В этом-то и проблема. Поэтому, если вы хотите избежать утечек памяти, ваш пользовательский загрузчик классов должен быть выпущен сборщиком мусора. Если загруженный код использует JDBC, вы скоро получите ошибку OutOfMemoryError, и все рухнет! Нехорошо!

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

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

Чтобы решить эту проблему, мы должны отменить регистрацию всех драйверов JDBC сразу после выполнения, чем закрыть URLClassLoader.

URL[] jars = new URL[] { /* The jars to be loaded */ }; //
try (URLClassLoader classLoader = new URLClassLoader(jars)) {
  Job job = classLoader.loadClass(Job.class.getName());
  job.execute();
  Collections.list(DriverManager.getDrivers()).forEach(driver -> {
    try {
      DriverManager.deregisterDriver(driver);
    } catch (SQLException e) {
      logger.error("Error unregistering driver!", e);
    }
  });
} 

Теперь давайте поищем загруженные классы:

  1. Если выполняемый код создает какой-либо поток, URLClassLoader не подходит для сборщика мусора.
  2. Если какая-то библиотека создаст какой-либо поток, та же проблема с # 1.
  3. Клиент MongoDB создает поток. 😫

Оригинал: “https://dev.to/vepo/java-memory-leak-for-jdbc-5dnn”