Что вам нужно знать в первую очередь
1. Программисты C/C++ самостоятельно управляют памятью, а память Java автоматически освобождается сборщиком мусора.
Хотя я не очень хорошо знаком с C++, я, вероятно, не допустил здесь ошибки здравого смысла.
2. Что такое утечка памяти?
Утечка памяти означает наличие в системе памяти, которая не может быть перезагружена, что иногда приводит к нехватке памяти или сбою системы.
В C/C++ утечки памяти происходят, когда выделенная память не освобождается.
3. В Java существует утечка памяти. Прежде чем продолжить обсуждение, мы должны признать это. Хотя в Java есть утечки памяти, вам в принципе не нужно об этом беспокоиться, особенно тем, кто не особо разбирается в самом коде.
Утечки памяти в Java определенно означают: существуют бесполезные объекты, которые не могут быть переработаны сборщиком мусора.
И даже если есть проблема с утечкой памяти, она может не проявиться.
4. Все параметры в Java передаются по значению.
По сути, нет никаких возражений против базовых типов, но мы не можем иметь никаких возражений против ссылочных типов.
Утечки памяти Java
1. Переполнение кучи памяти (outOfMemoryError: пространство кучи Java)
В спецификации JVM память в куче используется для создания экземпляров объектов и массивов.
Если разделить память кучи, ее также можно разделить на молодое поколение и старое поколение. Молодое поколение включает в себя райскую область и две области выживания.
При создании нового объекта процесс применения памяти выглядит следующим образом:
a. JVM сначала пытается выделить память, необходимую для нового объекта в области Eden;
б. Если объем памяти достаточен, приложение завершается, в противном случае выполняется следующий шаг;
в. JVM запускает youngGC и пытается освободить неактивные объекты в области Эдема. После релиза, если места Эдема все еще недостаточно для размещения новых объектов, она пытается поместить некоторые активные объекты из Эдема в область Выжившего;
d. Зона Выжившего используется как промежуточная зона обмена между Эдемом и старой областью. Когда в СТАРОЙ зоне достаточно места, объекты из зоны Выжившего будут перемещены в Старую зону, в противном случае они останутся в зоне Выжившего;
e. Если в СТАРОЙ области недостаточно места, JVM выполнит полный сбор мусора в СТАРОЙ области;
f. После полного GC, если области Survivor и OLD по-прежнему не могут хранить некоторые объекты, скопированные из Eden, из-за чего JVM не может создать область памяти для новых объектов в области Eden, появится «ошибка нехватки памяти»:
outOfMemoryError: пространство кучи Java
2. Переполнение памяти в области метода (outOfMemoryError: пространство пермгема)
В спецификации JVM область методов в основном хранит информацию о классах, константах, статических переменных и т. д.
Поэтому, если программа загружает слишком много классов или использует технологию динамического создания прокси, такую как отражение или gclib, это может вызвать переполнение памяти в этой области. Обычно сообщение об ошибке при возникновении переполнения памяти в этой области:
outOfMemoryError: пространство пермгема
3. Переполнение стека потока (java.lang.StackOverflowError)
Стек потока — это структура памяти, уникальная для потока, поэтому проблемы со стеком потока должны быть ошибками, возникающими во время работы потока.
Как правило, переполнение стека потоков вызвано слишком глубокой рекурсией или слишком большим количеством уровней вызовов методов.
Сообщение об ошибке при переполнении стека:
Ява. язык. StackOverflowError
Несколько сценариев утечек памяти:
1. Долгоживущие объекты содержат ссылки на недолговечные объекты.
Это наиболее распространенный сценарий утечек памяти и распространенная проблема при разработке кода.
Например: если локальные переменные кэшируются на глобальной статической карте и операция очистки не выполняется, карта со временем будет становиться все больше и больше, что приведет к утечкам памяти.
2. Измените значение параметра объекта в хеш-наборе, и этот параметр — это поле, используемое для расчета хэш-значения.
После сохранения объекта в коллекции HashSet поля объекта, которые участвуют в вычислении хэш-значения, не могут быть изменены, иначе измененное хеш-значение объекта будет отличаться от хэш-значения, когда оно изначально хранилось в коллекции HashSet. , в этом случае, даже если метод contains использует текущую ссылку на объект в качестве параметра для извлечения объекта из коллекции HashSet, он вернет результат, что объект не может быть найден, что также приведет к невозможности поиска. удалить текущий объект из коллекции HashSet, что приведет к утечке памяти.
3. Установите количество подключений и время отключения автомата.
Открытие очень ресурсоемкого соединения в течение длительного времени также может вызвать утечки памяти.
Давайте посмотрим на пример утечки памяти:
общественный класс Stack {частный Object[] elements=new Object[10]; частный int size = 0; size == 0) бросить новое EmptyStackException(); return elements[--size] } Private void SureCapacity(){ if(elements.length == size){ Object[] oldElements = элементы; элементы = новый объект [2 * elements. длина+1]; Система. arraycopy (oldElements, 0, элементы, 0, размер } }});
Вышеупомянутый принцип должен быть очень простым: если в стек добавляются 10 элементов, а затем все вытаскиваются, хотя стек пуст и нам ничего не нужно, этот объект не может быть переработан. Это соответствует двум требованиям утечки памяти. Состояние: бесполезен, не подлежит вторичной переработке.
Но даже существование такой вещи не обязательно может привести к каким-либо последствиям. Если этот стек будет использоваться меньше,
Это просто пустая трата нескольких К памяти. В любом случае, наша память уже достигла G, так какое влияние это окажет? Кроме того, эта штука скоро будет переработана, так какое это имеет значение? Давайте рассмотрим два примера ниже.
Пример 1
общественный класс Bad {общественный статический стек s = Stack () {s. нажать (новый объект()); с. pop(); //Здесь в объекте произошла утечка памяти. push(new Object()); //Вышеуказанный объект может быть переработан, что эквивалентно самовосстановлению}}
Поскольку он статический, он будет существовать до выхода из программы, но мы также можем видеть, что он имеет функцию самовосстановления.
То есть, если в вашем стеке не более 100 объектов, то не может быть переработано не более 100 объектов. На самом деле, это должно быть легко понять. В худшем случае все они бесполезны. , т.к. как только мы поставим новый прогресс, предыдущие ссылки естественно исчезнут!
Пример 2
общественный класс NotTooBad {общественный недействительный doSomething () { Stack s = новый Stack () s. push(новый объект()); //другой код s. pop();//Это также приводит к невозможности повторного использования объекта и утечке памяти. }//Выходим из метода, s автоматически становится недействительным, s может быть переработан, а ссылки внутри стека естественным образом исчезают, поэтому //здесь также можно выполнить самовосстановление, и можно сказать, что этот метод не имеет проблема с утечкой памяти, но она будет сдана позже // Отдается только GC, потому что закрыта и не открыта для внешнего мира. Можно сказать и выше. Код 99. 9999% // ситуаций не окажут никакого влияния. Конечно, если вы напишете такой код, никаких плохих последствий он не окажет, но // его точно можно назвать мусорным кодом. Никакого противоречия здесь нет! Я добавлю туда один. Пустой цикл for не окажет большого влияния, верно?}
Два приведенных выше примера тривиальны, но утечки памяти в C/C++ — это не плохо, а худшее.
Если они не переработаны в одном месте, их никогда нельзя будет переработать. Если вы будете часто вызывать этот метод, память будет израсходована!
Поскольку в Java также есть функция самовосстановления (я назвал ее сам и еще не подал заявку на патент), проблему утечки памяти в Java можно почти игнорировать, но тем, кто знает об этом, не следует ее совершать.
Чтобы избежать утечек памяти, при написании кода можно воспользоваться следующими рекомендациями:
1. Как можно раньше выпускайте ссылки на бесполезные объекты;
2. Используйте обработку строк, избегайте использования String и широко используйте StringBuffer. Каждый объект String должен занимать независимую область памяти;
3. Используйте статические переменные как можно меньше, т. к. статические переменные хранятся в постоянной генерации (области методов), а постоянная генерация практически не участвует в сборке мусора;
4. Избегайте создания объектов в циклах;
5. Открытие больших файлов или взятие слишком большого количества данных из базы данных за один раз может легко вызвать переполнение памяти, поэтому в этих местах следует примерно рассчитать максимальный объем данных и установить минимальное и максимальное значения необходимого объема памяти.