К слову об утечке памяти

Java сервер

предисловие

Эта тема уже является банальной, и причина, по которой я снова ее поднял, заключается в том, что детским ботинком рядом с блогером недавно была написана статья под названием «ThreadLocal Memory Leak», и я не буду ссылаться на нее, потому что она действительно написана. .(10 000 слов пропущено)
Дело в том, что после того, как я его написал, я был ошеломлен вопросом. Из гуманитарных соображений блогер без зазрения совести написал еще одну статью.

текст

определение

Во-первых, мы должны сначала поговорить о определении, потому что куча людей не понимают разницы между переполнением памяти и утечками памяти.
Недостаточно памяти:У тебя всего десять долларов, но я попросил у тебя сто долларов. Извините, у меня нет столько денег.(给不起)
Утечка памяти (MemoryLeak):У вас есть десять долларов, и я попрошу у вас один. Но бессовестный блогер, я не верну тебе деньги.(没退还)
связь:Множественные утечки памяти могут привести к переполнению памяти. (Блогер беззастенчиво просит у вас еще денег, а у вас их нет. Это правда.)

вред

хорошо, вы когда-нибудь сталкивались с ситуацией, когда java-программа все больше и больше застревает в проекте.
Из-за утечек памяти частоFull GC,а такжеFull GCЭто приведет к тому, что программа снова остановится и, наконец, произойдет сбой. Поэтому вы почувствуете, что ваша программа все больше и больше застревает, а потом продакт-менеджер вас презирает. Кстати, причина, по которой мы настраиваем JVM, состоит в том, чтобы уменьшитьFull GCвнешность.
Помню, однажды я столкнулся с проектом, который был в порядке, когда его только запускали. В результате, по мере накопления времени, сообщаетсяOutOfMemoryError: PermGen space.
Говоря об этомPermGen space, Внезапно из основной части блога вырвался прилив сил. Я должен представить эту область методов, но я остановлюсь здесь. Ведь речь идет не о «jvm от входа до отказа».
область метода: Из спецификации виртуальной машины Java, доступнойСовместно с каждым потокомизобласть оперативной памяти.它存储了Структурная информация для каждого класса, такие как пул констант времени выполнения (Runtime Constant Pool), данные полей и методов, содержимое байт-кода конструкторов и обычных методов.
Выше приведена спецификация, которая реализована по-разному на разных виртуальных машинах, наиболее типичная из нихПостоянная генерация (пространство PermGen)а такжеМетапространство.

До jdk1.8:Тот, который реализует область метода, называется постоянным поколением. Потому что давным-давно в java думали, что классы почтиеще, и редко выгружается и перерабатывается, поэтому даетпостоянное поколениепрозвище.следовательно, Если вы обнаружите, что куча и постоянная генерация в проекте постоянно растут, тенденции к снижению нет, и скорость рециркуляции просто не поспевает за скоростью роста. Само собой разумеется, эту ситуацию в принципе можно определить быть утечка памяти.

После jdk1.8:Область метода реализации называется метапространством. Java сложно настроить постоянное поколение. Метаданные в постоянном поколении могут меняться с каждымFull GCпроисходит движение. Да и размер пространства для постоянной генерации тоже сложно определить.следовательно, java решает разместить метаданные класса в локальной памяти, максимальное выделяемое пространство метапространства — это доступное пространство памяти системы. Таким образом, мы избегаем проблемы установки постоянного размера генерации.но, в этом случае, как только произойдет утечка памяти, она займет много вашей локальной памяти. Если вы заметили, использование локальной памяти в вашем проекте необычно велико. Ну это утечка памяти.

Как устранить неполадки

(1) пройтиjpsНайдите идентификатор процесса Java.
(2) пройтиtop -p [pid]Обнаружено, что использование памяти достигло максимального значения
(3)jstat -gccause pid 20000Вывод каждые 20 секундFull GCрезультат
(4) ОткрытиеFull GCСлишком много раз это в основном утечка памяти. генерироватьdumpфайл, с помощью инструментов, чтобы проанализировать, какой объект слишком много. В принципе можно найти проблему.

пример

В stackoverflow есть вопрос, как показано ниже

I just had an interview, and I was asked to create a memory leak with Java. Needless to say I felt pretty dumb having no clue on how to even start creating one.

Грубо говоря, потому что на собеседовании нужно написать от руки программу, которая сливает память, а потом человек, задающий вопрос, вдруг ошарашен, поэтому многие воротилы дают ответы один за другим.
Дело номер один
Этот пример из книги Алгоритмы (4-е издание), я немного упростил его

    class stack{    
        Object data[1000];    
        int top = 0;    
        public void push(Object o){        
            data[top++] = o;   
        }    
        public Object pop(Object o){ 
            return data[--top];
        }
    }скопировать код

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

    public Object pop(Object o){ 
        Object result = data[--top];
        data[top] = null;
        return result;
    }скопировать код

Случай 2
Это на самом деле куча примеров.Причины утечек памяти в этих примерах схожи, т.е.не закрывайте поток, в частности, это может быть файловый поток, поток сокетов, поток подключения к базе данных и т. д.
Детали следующие, файловый поток не отключен

try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}скопировать код

Другой пример: соединение не закрыто.

try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}скопировать код

Решение. . . Ах, мы должны быть в состоянии. . Вы говорите, что не настраиваютсяclose()метод.
Случай 3
Прежде чем говорить об этом примере, каждыйThreadLocalсуществуетTomcatЕсть ли у вас какие-либо идеи об утечке памяти, вызванной этим? Однако хочу сказать, что эта проблема с утечкой имеет мало отношения к самому ThreadLocal, я посмотрел примеры, приведенные на официальном сайте, и в основном она вызвана неправильным использованием.
Эта проблема задокументирована на официальном сайте Tomcat. адрес:https://wiki.apache.org/tomcat/MemoryLeakProtection
Однако этот пример на официальном сайте может оказаться непростым для понимания, поэтому мы вносим некоторые изменения.

public class HelloServlet extends HttpServlet{
    private static final long serialVersionUID = 1L;

    static class LocalVariable {
        private Long[] a = new Long[1024 * 1024 * 100];
    }

    final static ThreadLocal<LocalVariable> localVariable = new ThreadLocal<LocalVariable>();
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        localVariable.set(new LocalVariable());
    }
}скопировать код

Давайте посмотрим на конфигурацию sever.xml в conf.

  <!--The connectors can use a shared executor, you can define one or more named thread pools-->
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" 
        maxThreads="150" minSpareThreads="4"/>скопировать код

Максимальное количество потоков в пуле потоков — 150, а минимальное количество потоков — 4.
Компонент Connector в Tomcat отвечает за прием и обработку запросов.Каждый раз, когда приходит запрос, он отправляется в пул потоков для получения потока.
во время посещенияservletчас,ThreadLocalдобавлена ​​переменнаяnew LocalVariable()экземпляр, но неremove, чтобы переменная возвращалась в пул потоков вместе с потоком. Дополнительные визиты вservletНельзя использовать один и тот же поток в пуле рабочих потоков, что приведет к утечке памяти в нескольких потоках в пуле рабочих потоков.

Кроме того,servletизdoGetметод созданnew LocalVariable()когда используешьwebappclassloader.
Так
LocalVariableОбъект не выпущен ->LocalVariable.classнет выхода ->webappclassloaderне выпущены ->webappclassloaderВсе классы, которые были загружены, также не освобождались, что также вызывало утечку памяти.

К тому же тыeclipse, выполните операцию перезагрузки, поток в пуле рабочих потоков все еще существует, а поток в потокеthreadLocalПеременные не очищаются. При перезагрузке построит новыйwebappclassloader, повторите вышеуказанные шаги. После нескольких перезагрузок память переполняется.
Однако после Tomcat7.0 каждый раз, когда вы делаетеreload, который очистит потоки в пуле рабочих потоковthreadLocalsПеременная. Поэтому этой проблемы не будет после tomcat7.0.

ps:ThreadLocalИспользоватьTomcatВ среде службы следует отметить, что программа не запускается каждый раз, когда делается веб-запрос.ThreadLocalвсе уникальны.ThreadLocalЧто жизнь не равна разуRequestжизненный цикл.ThreadLocalжестко привязан к объекту потока из-заTomcatИспользуя пул потоков, потоки могут использоваться повторно.

Автор: Lonely Smoke Источник: http://rjzheng.cnblogs.com/Авторские права на эту статью принадлежат автору и блог-саду.Вы можете перепечатать ее, но это заявление должно быть сохранено без согласия автора, а ссылка на исходный текст должна быть дана в видном месте на странице статьи. , в противном случае сохраняется право на юридическую ответственность. Если вы считаете это полезным, вы можете нажать кнопку【рекомендовать】.