принудительно unregistring драйвер JDBC для предотвращения утечки памяти (intellij idea) [дубликат]

Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, он будет генерировать исключение NullReferenceException.

Пример:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

Вы можно просто избежать этого, проверив, является ли переменная не нулевой:

Person p = null;
if (p!=null)
{
    p.Name = "Harry"; // Not going to run to this point
}

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

Итак, если вы имеете дело со типами значений, NullReferenceExceptions не может произойти. Хотя вам нужно поддерживать оповещение при работе со ссылочными типами!

Только ссылочные типы, как следует из названия, могут содержать ссылки или буквально буквально ничто (или «нуль»). Если типы значений всегда содержат значение.

Типы ссылок (эти должны быть проверены):

  • динамический
  • объект
  • string

Типы значений (вы можете просто игнорировать эти):

  • Числовые типы
  • Интегральные типы
  • Типы с плавающей запятой
  • decimal
  • bool
  • Пользовательские структуры

284
задан BalusC 13 October 2011 в 03:07
поделиться

14 ответов

Начиная с версии 6.0.24, Tomcat поставляется с функцией обнаружения утечки памяти , что, в свою очередь, может привести к появлению подобных предупреждающих сообщений, когда в файле [app1] для веб-сервера есть JDBC 4.0-совместимый драйвер, auto- регистрирует сам во время запуска webapp, используя ServiceLoader API , но который сам не отключился deregister во время отключения Webapp. Это сообщение является чисто неофициальным, Tomcat уже принял меры по предотвращению утечки памяти.

Что вы можете сделать?

  1. Игнорировать эти предупреждения. Tomcat делает свою работу правильно. Фактическая ошибка находится в чужом коде (именно драйвер JDBC), а не в вашем. Будьте счастливы, что Tomcat выполнил свою работу должным образом и дождитесь, пока поставщик драйверов JDBC зафиксирует это, чтобы вы могли обновить драйвер. С другой стороны, вы не должны бросать JDBC-драйвер в webapp /WEB-INF/lib, но только на сервере /lib. Если вы все еще сохраняете его в файле /WEB-INF/lib в webapp, вам необходимо зарегистрировать его вручную и отменить его с помощью ServletContextListener.
  2. Перейти на Tomcat 6.0.23 или старше, чтобы вы не беспокоились об этих предупреждениях , Но он будет тихо хранить утечку памяти. Не знаю, хорошо ли это знать. Подобные утечки памяти являются одной из основных причин, стоящих перед проблемами OutOfMemoryError во время горячих рассылок Tomcat.
  3. Переместите JDBC-драйвер в папку /lib Tomcat и подключите пул данных к источнику данных для управления драйвером. Обратите внимание, что встроенный DBCP от Tomcat не отменяет регистрацию драйверов должным образом при закрытии. См. Также ошибку DBCP-322 , которая закрыта как WONTFIX. Вы хотели бы заменить DBCP другим пулом соединений, который лучше выполняет свою работу, чем DBCP. Например, HikariCP , BoneCP или, возможно, Tomcat JDBC Pool .
273
ответ дан BalusC 26 August 2018 в 06:24
поделиться

В вашем контексте контекст-слушатель контекстного методаDestroyed () вручную отмените регистрацию драйверов:

        // This manually deregisters JDBC driver, which prevents Tomcat 7 from complaining about memory leaks wrto this class
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
                LOG.log(Level.INFO, String.format("deregistering jdbc driver: %s", driver));
            } catch (SQLException e) {
                LOG.log(Level.SEVERE, String.format("Error deregistering driver %s", driver), e);
            }

        }
154
ответ дан ae6rt 26 August 2018 в 06:24
поделиться

Я столкнулся с этой проблемой, когда я развертывал приложение Grails на AWS. Это вопрос драйвера JDBC по умолчанию для драйвера org.h2. Как вы можете видеть это в Datasource.groovy внутри вашей папки конфигурации. Как вы можете видеть ниже:

dataSource {
    pooled = true
    jmxExport = true
    driverClassName = "org.h2.Driver"   // make this one comment
    username = "sa"
    password = ""
}

Прокомментируйте эти строки везде, где упоминается org.h2.Driver в файле datasource.groovy, если вы не используете эту базу данных. В противном случае вам нужно загрузить этот файл jar базы данных.

Спасибо.

0
ответ дан AJT_82 26 August 2018 в 06:24
поделиться

Решение для развертываний для каждого приложения

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

Важно: это должен использоваться ТОЛЬКО, когда баннер драйвера развертывается в WEB-INF / lib, а не в Tomcat / lib, как многие из них предлагают, так что каждое приложение может позаботиться о своем собственном драйвере и запустить на нетронутом Tomcat. Таким образом, это должно быть IMHO.

Просто настройте слушателя в вашем web.xml перед любым другим и наслаждайтесь.

добавить в верхней части web.xml :

<listener>
    <listener-class>utils.db.OjdbcDriverRegistrationListener</listener-class>    
</listener>

сохранить как utils / db / OjdbcDriverRegistrationListener.java :

package utils.db;

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import oracle.jdbc.OracleDriver;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Registers and unregisters the Oracle JDBC driver.
 * 
 * Use only when the ojdbc jar is deployed inside the webapp (not as an
 * appserver lib)
 */
public class OjdbcDriverRegistrationListener implements ServletContextListener {

    private static final Logger LOG = LoggerFactory
            .getLogger(OjdbcDriverRegistrationListener.class);

    private Driver driver = null;

    /**
     * Registers the Oracle JDBC driver
     */
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        this.driver = new OracleDriver(); // load and instantiate the class
        boolean skipRegistration = false;
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            if (driver instanceof OracleDriver) {
                OracleDriver alreadyRegistered = (OracleDriver) driver;
                if (alreadyRegistered.getClass() == this.driver.getClass()) {
                    // same class in the VM already registered itself
                    skipRegistration = true;
                    this.driver = alreadyRegistered;
                    break;
                }
            }
        }

        try {
            if (!skipRegistration) {
                DriverManager.registerDriver(driver);
            } else {
                LOG.debug("driver was registered automatically");
            }
            LOG.info(String.format("registered jdbc driver: %s v%d.%d", driver,
                    driver.getMajorVersion(), driver.getMinorVersion()));
        } catch (SQLException e) {
            LOG.error(
                    "Error registering oracle driver: " + 
                            "database connectivity might be unavailable!",
                    e);
            throw new RuntimeException(e);
        }
    }

    /**
     * Deregisters JDBC driver
     * 
     * Prevents Tomcat 7 from complaining about memory leaks.
     */
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        if (this.driver != null) {
            try {
                DriverManager.deregisterDriver(driver);
                LOG.info(String.format("deregistering jdbc driver: %s", driver));
            } catch (SQLException e) {
                LOG.warn(
                        String.format("Error deregistering driver %s", driver),
                        e);
            }
            this.driver = null;
        } else {
            LOG.warn("No driver to deregister");
        }

    }

}
8
ответ дан Andrea Ratto 26 August 2018 в 06:24
поделиться

Я обнаружил, что реализация простого метода destroy () для деинсталляции любых драйверов JDBC прекрасно работает.

/**
 * Destroys the servlet cleanly by unloading JDBC drivers.
 * 
 * @see javax.servlet.GenericServlet#destroy()
 */
public void destroy() {
    String prefix = getClass().getSimpleName() +" destroy() ";
    ServletContext ctx = getServletContext();
    try {
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while(drivers.hasMoreElements()) {
            DriverManager.deregisterDriver(drivers.nextElement());
        }
    } catch(Exception e) {
        ctx.log(prefix + "Exception caught while deregistering JDBC drivers", e);
    }
    ctx.log(prefix + "complete");
}
6
ответ дан animuson 26 August 2018 в 06:24
поделиться

Я нашел ту же проблему с Tomcat версии 6.026.

Я использовал Mysql JDBC.jar в библиотеке WebAPP, а также в TOMCAT Lib.

Чтобы исправить это, удалив Jar из папки TOMCAT lib.

Итак, я понимаю, что TOMCAT правильно обрабатывает утечку памяти JDBC. Но если JSB JQB JQB дублируется в WebApp и Tomcat Lib, Tomcat сможет обрабатывать только банку в папке Tomcat Lib.

0
ответ дан Bharat 26 August 2018 в 06:24
поделиться

Я добавлю к этому что-то, что я нашел на форумах Spring. Если вы переместите JDBC-драйвер в папку tomcat lib, вместо того, чтобы развернуть его с помощью webapp, предупреждение, похоже, исчезнет. Я могу подтвердить, что это сработало для меня

http://forum.springsource.org/showthread.php?87335-Failure-to-unregister-the-MySQL-JDBC-Driver&p= 334883 # post334883

6
ответ дан Collin Peters 26 August 2018 в 06:24
поделиться

У меня была аналогичная проблема, но дополнительно я получал ошибку Java Heap Space в любое время, когда я модифицировал / сохранил JSP-страницы с сервером Tomcat, поэтому контекст не был полностью перезаряжен.

Мои версии были Apache Tomcat 6.0.29 и JDK 6u12.

Обновление JDK до 6u21, как предлагается в Ссылки в разделе URL http: / /wiki.apache.org/tomcat/MemoryLeakProtection решил проблему Java Heap Space (контекст теперь перезагружает OK), хотя ошибка драйвера JDBC все еще появляется.

2
ответ дан Francisco Alvarado 26 August 2018 в 06:24
поделиться

Удаляет приложение (tomcat6). Файлы conf сохраняются. Это как-то ломается. Я не уверен, как это делается.

-10
ответ дан Ivan Georgiev 26 August 2018 в 06:24
поделиться

Я вижу, что этот вопрос много. Да, Tomcat 7 автоматически отменяет регистрацию, но это ДЕЙСТВИТЕЛЬНО контролирует ваш код и хорошую практику кодирования? Конечно, вы хотите знать, что у вас есть правильный код, чтобы закрыть все ваши объекты, отключить потоки пула подключений к базе данных и избавиться от всех предупреждений.

Вот как я это делаю.

Шаг 1: зарегистрируйте прослушиватель

web.xml

<listener>
    <listener-class>com.mysite.MySpecialListener</listener-class>
</listener>

Шаг 2: Внедрить слушателя

com.mysite.MySpecialListener.java

public class MySpecialListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // On Application Startup, please…

        // Usually I'll make a singleton in here, set up my pool, etc.
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // On Application Shutdown, please…

        // 1. Go fetch that DataSource
        Context initContext = new InitialContext();
        Context envContext  = (Context)initContext.lookup("java:/comp/env");
        DataSource datasource = (DataSource)envContext.lookup("jdbc/database");

        // 2. Deregister Driver
        try {
            java.sql.Driver mySqlDriver = DriverManager.getDriver("jdbc:mysql://localhost:3306/");
            DriverManager.deregisterDriver(mySqlDriver);
        } catch (SQLException ex) {
            logger.info("Could not deregister driver:".concat(ex.getMessage()));
        } 

        // 3. For added safety, remove the reference to dataSource for GC to enjoy.
        dataSource = null;
    }

}

Пожалуйста, не стесняйтесь комментировать и / или добавить ...

24
ответ дан kenor 26 August 2018 в 06:24
поделиться

Чтобы предотвратить утечку памяти, просто отмените регистрацию драйвера при отключении контекста.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mywebsite</groupId>
    <artifactId>emusicstore</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.9</source>
                    <target>1.9</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <!-- ... -->

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.0.1.Final</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.1.Final</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

MyWebAppContextListener.java

package com.emusicstore.utils;

import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

public class MyWebAppContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("************** Starting up! **************");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("************** Shutting down! **************");
        System.out.println("Destroying Context...");
        System.out.println("Calling MySQL AbandonedConnectionCleanupThread checkedShutdown");
        AbandonedConnectionCleanupThread.checkedShutdown();

        ClassLoader cl = Thread.currentThread().getContextClassLoader();

        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();

            if (driver.getClass().getClassLoader() == cl) {
                try {
                    System.out.println("Deregistering JDBC driver {}");
                    DriverManager.deregisterDriver(driver);

                } catch (SQLException ex) {
                    System.out.println("Error deregistering JDBC driver {}");
                    ex.printStackTrace();
                }
            } else {
                System.out.println("Not deregistering JDBC driver {} as it does not belong to this webapp's ClassLoader");
            }
        }
    }

}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <listener>
        <listener-class>com.emusicstore.utils.MyWebAppContextListener</listener-class>
    </listener>

<!-- ... -->

</web-app>

Источник , который вдохновил меня на исправление этой ошибки.

0
ответ дан King-Wizard 26 August 2018 в 06:24
поделиться

Это чисто проблема регистрации / снятия регистрации с сервера в mysql`s driver или tomcats webapp-classloader. Скопируйте mysql-драйвер в папку tomcats lib (так что он загружен jvm напрямую, а не tomcat), и сообщение исчезнет. Это приводит к выгрузке драйвера mysql jdbc только при отключении JVM, и никто не заботится о утечке памяти.

14
ответ дан Lawrence Dol 26 August 2018 в 06:24
поделиться

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

Тем не менее, методология полного снятия регистрации водителя опасна. Некоторые драйверы, возвращаемые методом DriverManager.getDrivers(), возможно, были загружены родительским ClassLoader (то есть загрузчиком классов контейнера сервлетов), а не классом ClassLoader для контекста webapp (например, они могут находиться в папке lib контейнера, а не в веб-папке, и поэтому совместно используются весь контейнер).

Поэтому следует проверить, что ClassLoader для каждого драйвера является ClassLoader Webapp, прежде чем отменять его регистрацию. Итак, в вашем контексте contextTestroyed () метода ContextListener:

public final void contextDestroyed(ServletContextEvent sce) {
    // ... First close any background tasks which may be using the DB ...
    // ... Then close any DB connection pools ...

    // Now deregister JDBC drivers in this context's ClassLoader:
    // Get the webapp's ClassLoader
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    // Loop through all drivers
    Enumeration<Driver> drivers = DriverManager.getDrivers();
    while (drivers.hasMoreElements()) {
        Driver driver = drivers.nextElement();
        if (driver.getClass().getClassLoader() == cl) {
            // This driver was registered by the webapp's ClassLoader, so deregister it:
            try {
                log.info("Deregistering JDBC driver {}", driver);
                DriverManager.deregisterDriver(driver);
            } catch (SQLException ex) {
                log.error("Error deregistering JDBC driver {}", driver, ex);
            }
        } else {
            // driver was not registered by the webapp's ClassLoader and may be in use elsewhere
            log.trace("Not deregistering JDBC driver {} as it does not belong to this webapp's ClassLoader", driver);
        }
    }
}
72
ответ дан megaflop 26 August 2018 в 06:24
поделиться

Если вы получаете это сообщение от измененного военного изменения Maven, укажите область действия драйвера JDBC и поместите его копию в каталог lib. Например:

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.18</version>
  <!-- put a copy in /usr/share/tomcat7/lib -->
  <scope>provided</scope>
</dependency>
8
ответ дан TimP 26 August 2018 в 06:24
поделиться
Другие вопросы по тегам:

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