Как устранить утечку памяти
Перейти к содержимому

Как устранить утечку памяти

  • автор:

Как исправить утечку памяти?

@ВладимирМартьянов, если бы все было так просто. Когда переменной str присваивается новое значение, я теряю доступ к старому (в этом месте и есть утечка). Если вызвать free(str) до операции присваивания, то я не смогу получить значение перменной str .

30 авг 2016 в 15:34

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

30 авг 2016 в 15:37
@ВладимирМартьянов, тогда каким образом переменная str получит новое значение?
30 авг 2016 в 15:40
@ВладимирМартьянов не проще код в ответ написать?
30 авг 2016 в 15:41

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

char * str = strrem("test_string", "s); //Ошибка синтаксиса, не соберется. str = strrem(str, "_"); 

Учитывая что strrem() выделяет память через calloc() и strrem() вызывается дважды, у вас должно быть ДВА указателя для хранения выделенной памяти, чтобы потом вызвать free() для обоих.

char* str = strrem(. ); char* ptr1 = str; str = strrem(. ); . //Тут аццкей кодес free(str); //освобождение от первого strrem free(ptr1); //освобождение от второго strrem 

Отслеживать
ответ дан 30 авг 2016 в 16:13
Владимир Мартьянов Владимир Мартьянов
9,649 4 4 золотых знака 21 21 серебряный знак 35 35 бронзовых знаков

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

При этом Вы не хотите освобождать память (вызывать free() ) первого аргумента внутри strrem() (возможно из-за того, что иногда это константа), не хотите писать «лишние» строчки кода, а всегда хотите иметь возможность использовать такую запись:

str = strrem(str, arg2); 

и избежать утечек памяти.

Обобщая идею в ответе @Владимир Мартьянов, все это (в основном экономию строчек) можно реализовать примерно так:

char *str, *prev = 0; . str = strrem("xaxa", "xoxo"); . while (. ) < free(prev), prev = 0; // не забудьте обнулять, чтобы потом не упасть от повторного освобождения той же памяти str = strrem(prev = str, "abc"); . // кстати, тут доступны как старое (в prev), так и новое значения str >. free(str); free(prev); // поскольку мы обнуляем prev после free(prev), то это безопасно 

Т.е. в тех местах, где Вы вызываете strrem() с аргументом, память которого далее должна быть освобождена, Вы сразу (в точке вызова) запоминаете этот адрес.

При желании (и имея перед глазами больше разных случаев использования strrem ) все такие вызовы с освобождением желательно оформить в виде макросов (при достаточном их разнообразии скорее всего переменную prev вообще удастся убрать с глаз долой).

Устранение утечек памяти

Если вы разрабатываете приложения на Vue, тогда вам нужно следить за утечками памяти. Эта проблема особенно важна в одностраничных приложениях (SPA), потому что идея использования SPA состоит в отсутствии пользователям необходимости обновлять страницы браузера, поэтому задачей JavaScript приложения также будет и очистка в компонентах от лишнего.

Утечки памяти в приложениях Vue обычно не исходят от самого Vue, скорее они могут происходить при интеграции других библиотек в приложение.

Простой пример

В этом примере показана утечка памяти, вызванная использованием библиотеки Choices.js внутри компонента Vue без очистки ресурсов должным образом. Далее мы покажем как удалять остающееся после Choices.js и избежать утечки памяти.

В примере ниже, мы загружаем в select большое число вариантов выбора, а также используем кнопку для отображения/скрытия с помощью директивы v-if, чтобы добавлять и удалять список из виртуального DOM. Проблема в этом примере заключается в том, что директива v-if удаляет родительский элемент из DOM, но не выполняет дополнительную очистку DOM от частей, созданных Choices.js, что и вызывает утечку памяти.

link rel="stylesheet prefetch" href="https://joshuajohnson.co.uk/Choices/assets/styles/css/choices.min.css?version=3.0.3">
script src="https://joshuajohnson.co.uk/Choices/assets/scripts/dist/choices.min.js?version=3.0.3"> script>

div id="app">
button
v-if="showChoices"
@click="hide"
>Скрыть button>
button
v-if="!showChoices"
@click="show"
>Показать button>
div v-if="showChoices">
select id="choices-single-default"> select>
div>
div>
new Vue({ 
el: "#app",
data: function ( ) {
return {
showChoices: true
}
},
mounted: function ( ) {
this.initializeChoices()
},
methods: {
initializeChoices: function ( ) {
let list = []
// загружаем в наш select множество вариантов,
// что вызовет большое использование памяти
for (let i = 0; i < 1000; i++) {
list.push({
label: "Item " + i,
value: i
})
}
new Choices("#choices-single-default", {
searchEnabled: true,
removeItemButton: true,
choices: list
})
},
show: function ( ) {
this.showChoices = true
this.$nextTick(() => {
this.initializeChoices()
})
},
hide: function ( ) {
this.showChoices = false
}
}
})

Чтобы увидеть эту утечку памяти в действии, откройте этот пример на CodePen с помощью Chrome и затем откройте Диспетчер задач Chrome. Чтобы открыть на Mac, выберите в верхнем меню > Окно > Диспетчер задач или на Windows с помощью сочетания клавиш Shift+Esc. Теперь, нажимайте кнопку показать/скрыть около 50 раз. Вы сможете увидеть увеличение использованной памяти в Диспетчере задач Chrome, которая не будет освобождена.

Пример утечки памяти

Исправление утечки памяти

В примере выше, мы можем использовать наш метод hide() для выполнения очистки и устранения утечки памяти перед удалением select из DOM. Для этого мы будем хранить свойство в нашем экземпляре Vue и будем использовать API плагина Choices в методе destroy() для выполнения необходимых операций очистки.

Проверьте использование памяти в обновлённом примере на CodePen.

new Vue({ 
el: "#app",
data: function ( ) {
return {
showChoices: true,
choicesSelect: null
}
},
mounted: function ( ) {
this.initializeChoices()
},
methods: {
initializeChoices: function ( ) {
let list = []
for (let i = 0; i < 1000; i++) {
list.push({
label: "Item " + i,
value: i
})
}
// Сохраняем ссылку на экземпляр плагина
// в объекте data экземпляра Vue
this.choicesSelect = new Choices("#choices-single-default", {
searchEnabled: true,
removeItemButton: true,
choices: list
})
},
show: function ( ) {
this.showChoices = true
this.$nextTick(() => {
this.initializeChoices()
})
},
hide: function ( ) {
// теперь мы можем использовать ссылку на Choices
// для выполнения необходимых плагину операций очистки
// перед удалением элементов из DOM
this.choicesSelect.destroy()
this.showChoices = false
}
}
})

Подробнее о значимости

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

Определите типы устройств, которые ваши пользователи могут использовать и какой сценарий работы с приложением может быть. Могут ли они использовать ноутбуки или мобильные устройства с небольшим количеством памяти? Будут ли ваши пользователи обычно совершать много переходов между страницами приложения? Если ответы на эти вопросы — «да», тогда хорошие практики управления памятью могут помочь избежать вам наихудшего сценария сбоя браузера пользователя. Даже если ни один ответ на вопрос не будет «да», вы по-прежнему можете ухудшить производительность вашего приложения при длительном использовании, если не будете осторожны.

Пример из жизни

В примере выше, мы использовали директиву v-if чтобы проиллюстрировать утечку памяти, но более распространённый сценарий из жизни возникает при использовании vue-router для маршрутизации по компонентам в одностраничном приложении (SPA).

Также, как и директива v-if , vue-router удаляет элементы из виртуального DOM и заменяет их новыми элементами при навигации пользователя по вашему приложению. Хук жизненного цикла beforeDestroy() — хорошее место для решения подобной проблемы в приложениях на основе vue-router .

Мы могли бы переместить нашу очистку в хук beforeDestroy() следующим образом:

beforeDestroy: function ( ) { 
this.choicesSelect.destroy()
}

Альтернативы

Мы обсудили управление памятью при удалении элементов, но что, если вы намеренно хотите сохранять состояние и сохранить элементы в памяти? В этом случае вы можете использовать встроенный компонент keep-alive.

Когда вы оборачиваете компонент с помощью keep-alive , его состояние будет сохранено, и следовательно, останется в памяти.

button @click="show = false">Скрыть button>
keep-alive>

my-component v-if="show">
my-component>
keep-alive>

Эта техника может быть полезна для улучшения пользовательского опыта работы с приложением. Например, представьте, что пользователь начинает вводить комментарий в текстовое поле и затем решает перейти на другую страницу. Если пользователь вернётся обратно, то его комментарий останется сохранён в поле.

С тех пор, как начнёте использовать keep-alive, у вас появится доступ к двум дополнительным хукам жизненного цикла: activated и deactivated . Если вы хотите выполнить очистку или изменить данные при удалении компонента с keep-alive, вы можете сделать это в хуке deactivated .

deactivated: function ( ) { 
// удаление любых данных, которые не требуется хранить
}

Подытожим

Vue позволяет легко разрабатывать потрясающие реактивные JavaScript-приложения, но вам всё равно нужно уделять внимание утечкам памяти. Эти утечки обычно происходят при использовании дополнительных сторонних библиотек, которые манипулируют DOM вне Vue. Не забудьте проверить ваше приложение на утечки памяти и предпринять соответствующие шаги для добавления необходимых очисток в компонентах, где это необходимо.

Обнаружили ошибку или хотите добавить что-то своё в документацию? Измените эту страницу на GitHub! Опубликовано на Netlify .

Как исправить Windows 10ную утечку памяти

Сводка: На этой странице содержится информация о утечек памяти в Windows 10

  • Содержание статьи
  • Свойства статьи
  • Оцените эту статью

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

Содержание статьи

Симптомы

Утечки памяти указывают на Windows потери памяти, которая вызвана приложениями. Это происходит, когда приложение использует больше RAM, чем обычно происходит, и это приводит к тому, что система будет испытывать проблемы при выполнении даже основных задач.

Содержание:

  1. Открыть окно «Диспетчер задач»
  2. Загрузочные программы
  3. Обновление драйверов
Причина

Открыть окно «Диспетчер задач»

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

  1. Чтобы запустить диспетчер задач, нажмите клавиши CTRL + SHIFT + ESC
  2. На вкладке « процессы » установите и завершите задачу (приложение), которая занимает больше памяти.

Примечание. Не закрывайте приложения системы, так как это может привести к неправильной работе системы.

Загрузочные программы

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

  1. Нажмите клавиши CTRL + SHIFT + ESC , чтобы запустить диспетчер задач.
  2. Выберите вкладку Автозагрузка .
  3. Выберите приложение, которое потребляет избыточную память и отключите ее.
Разрешение

Обновление драйверов

Устаревшие драйверы могут привести к утечке памяти. Первые драйверы, которые необходимо проверит, — это графические, звуковые и сетевые драйверы, так как они являются типичными причинами проблем с утечкой памяти.

Чтобы получить последние версии драйверов, посетите веб-сайт поддержки драйверов.

Кофе-брейк #235. 10 распространенных утечек памяти в Java и способы их устранения

Java-университет

Кофе-брейк #235. 10 распространенных утечек памяти в Java и способы их устранения - 1

Источник: MediumВ этом руководстве изложены оптимальные решения по поиску и устранению утечек памяти в Java на этапе кодирования.В перечень распространенных утечек памяти в Java входят:

  1. Статические поля и коллекции.
  2. Незакрытые ресурсы.
  3. Переменные ThreadLocal .
  4. Неограниченное кэширование.
  5. Неправильное использование слушателей событий (Event Listeners).
  6. Неубранные корни сборки мусора.
  7. Неуправляемые пулы потоков.
  8. Неправильное использование шаблона Singleton .
  9. Глубокие и сложные графы объектов.
  10. Сторонние библиотеки.

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

1. Статические поля и коллекции

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

Пример: статическая HashMap

Рассмотрим следующий фрагмент кода, в котором объект User помещается в статическую HashMap и никогда не удаляется.

 public class User < private String userName; // статическая HashMap, хранящая объекты пользователя private static Mapusers = new HashMap<>(); // Constructor public User(String userName) < this.userName = userName; users.put(userName, this); >// другие методы > 

Объекты User , помещенные в статическую HashMap под названием users , никогда не будут удалены сборщиком мусора, если только они не будут явно удалены из HashMap .

Решение проблемы:

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

 private static Map users = new WeakHashMap<>(); 

2. Незакрытые ресурсы

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

Пример: FileInputStream

Рассмотрим следующий фрагмент кода, который считывает данные из файла:

 public void readDataFromFile(String filePath) < try < FileInputStream fis = new FileInputStream(filePath); // Чтение данных из файла >catch (IOException e) < e.printStackTrace(); >> 

В данном примере FileInputStream не закрывается после использования, что приводит к утечке памяти.

Решение проблемы:

Всегда закрывайте ресурсы после того, как они больше не нужны. В Java 7 появилась функция try-with-resources , которая автоматически закрывает ресурсы при завершении блока.

 public void readDataFromFile(String filePath) < try (FileInputStream fis = new FileInputStream(filePath)) < // Чтение данных из файла >catch (IOException e) < e.printStackTrace(); >> 

3. Переменные ThreadLocal

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

Пример: Пользовательская переменная ThreadLocal
 public class CustomThreadLocal < public static final ThreadLocaldateFormatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd")); public String formatDate(Date date) < return dateFormatter.get().format(date); >> 

В этом примере мы сохраняем объект SimpleDateFormat в переменной ThreadLocal . Но если поток не управляется, то объект SimpleDateFormat никогда не будет удален сборщиком мусора.

Решение проблемы:

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

 public void cleanup()

4. Неограниченное кэширование

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

Пример: кэш на основе HashMap
 public class SimpleCache < private final Mapcache = new HashMap<>(); public BigDecimal getValue(String key) < BigDecimal value = cache.get(key); if (value == null) < value = calculateValue(key); cache.put(key, value); >return value; > private BigDecimal calculateValue(String key) < // Длительная операция по вычислению значения return new BigDecimal("123.45"); >> 

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

Решение проблемы:

Ограничьте размер кеша и используйте подходящую политику замещения данных. Такие библиотеки, как Google Guava, предоставляют разработчикам настраиваемые решения для кэширования. Вот пример использования CacheBuilder от Guava:

 import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; public class LimitedCache < private final Cachecache = CacheBuilder.newBuilder() .maximumSize(1000) .build(); public BigDecimal getValue(String key) < BigDecimal value = cache.getIfPresent(key); if (value == null) < value = calculateValue(key); cache.put(key, value); >return value; > private BigDecimal calculateValue(String key) < // Длительная операция по вычислению значения return new BigDecimal("123.45"); >> 

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

5. Неправильное использование слушателей событий (Event Listeners)

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

Пример: слушатель анонимных действий
 class MyButton < private Listlisteners = new ArrayList<>(); public void addActionListener(ActionListener listener) < listeners.add(listener); >public void doAction() < for (ActionListener listener : listeners) < listener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "Click")); >> > public class Main < public static void main(String[] args) < MyButton button = new MyButton(); for (int i = 0; i < 10; i++) < // Добавление новых анонимных слушателей button.addActionListener(e ->System.out.println("Button clicked")); > > > 

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

Решение проблемы:

Чтобы предотвратить утечку памяти, вызванную слушателями событий, убедитесь, что они удаляются, когда больше не нужны. Одним из решений является использование WeakReference для хранения слушателя событий. Другой подход заключается в том, чтобы гарантировать, что любые долгоживущие или большие объекты, удерживающие слушатель, удалят его, как только они закончат с ним работать:

 button.removeActionListener(listener); 
6. Неубранные корни сборки мусора

Корни (Roots) сборки мусора — это объекты, которые всегда доступны и, следовательно, никогда не подвергаются сборке мусора. Некоторые из них включают статические переменные, потоки и локальные переменные в основном потоке. Если корни сборки мусора содержат ссылки на ненужные объекты, они предотвращают сборку мусора для этих объектов.

Пример: объект не собран мусором
 public static List numbers = new ArrayList<>(); public void getData() < while (dataAvailable()) < BigDecimal number = getNextNumber(); numbers.add(number); >processData(numbers); > 

В этом примере статическая переменная numbers содержит ссылки на объекты. Пока список numbers не очищен, он вызывает утечку памяти в приложении.

Решение проблемы:

Убедитесь, что корни сборки мусора освобождают объекты, когда они больше не нужны. В примере ниже мы можем очистить список numbers после завершения обработки:

 public void getData() < while (dataAvailable()) < BigDecimal number = getNextNumber(); numbers.add(number); >processData(numbers); numbers.clear(); // Освобождаем память > 

7. Плохо управляемые пулы потоков

Неправильное управление пулами потоков может привести к утечкам памяти. В основном это происходит, когда приложения Java используют пулы потоков с неограниченным числом потоков или не освобождают ресурсы.

Пример: незакрытые исполнители (Executors)
 public class Main < public static void main(String[] args) < ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 100; i++) < executorService.submit(() ->< // Какие-то действия >); > > > 

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

Решение проблемы:

Чтобы устранить утечки памяти, связанные с пулами потоков, убедитесь, что ресурсы высвобождаются, а потоки завершаются контролируемым образом. Завершите работу ExecutorService правильно, как только все задачи будут выполнены:

 public class Main < public static void main(String[] args) < ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 100; i++) < executorService.submit(() ->< // Какие-то действия >); > // Завершение работы ExecutorService executorService.shutdown(); > > 

8. Неправильное использование шаблона Singleton

Объекты-синглтоны предназначены для того, чтобы иметь только один экземпляр в течение жизненного цикла приложения. Однако неправильное использование шаблона Singleton может привести к утечке памяти.

Пример: объект Singleton
 public class Singleton < private static final Singleton instance = new Singleton(); private Listdata = new ArrayList<>(); private Singleton() <> public static Singleton getInstance() < return instance; >public void addData(BigDecimal value) < data.add(value); >// Другие методы > 

В этом примере объект Singleton содержит ссылки на объекты BigDecimal через свой список data . Этот список может расти бесконечно, что и приводит к утечкам памяти.

Решение проблемы:

Чтобы избежать утечек памяти, связанных с объектами Singleton , будьте осторожны при использовании шаблона и убедитесь, что вы освобождаете или ограничиваете ресурсы, потребляемые экземпляром Singleton :

 public class Singleton < private static final Singleton instance = new Singleton(); private Listdata = new ArrayList<>(); private Singleton() <> public static Singleton getInstance() < return instance; >public void addData(BigDecimal value) < data.add(value); >public void clearData() < data.clear(); >// Другие методы > 

В улучшенном решении метод clearData добавлен для освобождения ресурсов, удерживаемых экземпляром Singleton .

9. Глубокие и сложные графы объектов

Приложениями со сложными графами объектов может стать трудно управляемым, что затрудняет определение того, когда объекты могут быть удалены сборщиком мусора. Из-за этого могут возникать утечки памяти, если недоступные объекты остаются прикрепленными к графу объектов.

Пример: клиент и заказы
 public class Customer < private Listorders = new ArrayList<>(); public void addOrder(Order order) < orders.add(order); >// Геттеры и сеттеры > public class Order < private Listitems = new ArrayList<>(); public void addItem(Item item) < items.add(item); >// Геттеры и сеттеры > public class Item < private String name; private BigDecimal price; // Геттеры и сеттеры >

В данном примере объекты Customer имеют ссылки на объекты Order , а объекты Order имеют ссылки на объекты Item . Если объект Customer больше не нужен, но не отделен от графа объектов должным образом, то могут возникнуть утечки памяти.

Решение проблемы:

Убедитесь, что вы правильно управляете ссылками на объекты и отношениями. Чтобы избежать таких утечек памяти, используйте такие методы, как шаблон Observer или слабые ссылки (weak references):

 import java.lang.ref.WeakReference; public class Customer < private List> orders = new ArrayList<>(); public void addOrder(Order order) < orders.add(new WeakReference<>(order)); > // Геттеры и сеттеры > 

10. Сторонние библиотеки

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

Пример: Анализ XML

Некоторые синтаксические анализаторы XML, такие как Xerces, могут вызывать утечки памяти при использовании пользовательских EntityResolvers .

Решение проблемы:
  1. Обновляйте библиотеки до последней стабильной версии.
  2. Изучите работу библиотеки и любые потенциальные проблемы с памятью.
  3. Настройте библиотеку в соответствии с рекомендациями и рекомендациями.
 // Настройка EntityResolver public class CustomEntityResolver implements EntityResolver < // Реализация для разрешения сущностей >

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *