Как исправить утечку памяти?
@ВладимирМартьянов, если бы все было так просто. Когда переменной 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, чем обычно происходит, и это приводит к тому, что система будет испытывать проблемы при выполнении даже основных задач.
Содержание:
- Открыть окно «Диспетчер задач»
- Загрузочные программы
- Обновление драйверов
Причина
Открыть окно «Диспетчер задач»
Чтобы использовать диспетчер задач для того, чтобы узнать, какой объем памяти использует каждое приложение, выполните указанные ниже действия.
- Чтобы запустить диспетчер задач, нажмите клавиши CTRL + SHIFT + ESC
- На вкладке « процессы » установите и завершите задачу (приложение), которая занимает больше памяти.
Примечание. Не закрывайте приложения системы, так как это может привести к неправильной работе системы.
Загрузочные программы
Чтобы отключить загрузочные программы, потребляющие слишком много памяти, выполните указанные ниже действия.
- Нажмите клавиши CTRL + SHIFT + ESC , чтобы запустить диспетчер задач.
- Выберите вкладку Автозагрузка .
- Выберите приложение, которое потребляет избыточную память и отключите ее.
Разрешение
Обновление драйверов
Устаревшие драйверы могут привести к утечке памяти. Первые драйверы, которые необходимо проверит, — это графические, звуковые и сетевые драйверы, так как они являются типичными причинами проблем с утечкой памяти.
Чтобы получить последние версии драйверов, посетите веб-сайт поддержки драйверов.
Кофе-брейк #235. 10 распространенных утечек памяти в Java и способы их устранения
Источник: MediumВ этом руководстве изложены оптимальные решения по поиску и устранению утечек памяти в Java на этапе кодирования.В перечень распространенных утечек памяти в Java входят:
- Статические поля и коллекции.
- Незакрытые ресурсы.
- Переменные ThreadLocal .
- Неограниченное кэширование.
- Неправильное использование слушателей событий (Event Listeners).
- Неубранные корни сборки мусора.
- Неуправляемые пулы потоков.
- Неправильное использование шаблона Singleton .
- Глубокие и сложные графы объектов.
- Сторонние библиотеки.
Поскольку с утечками памяти лучше (и дешевле всего) всего бороться на этапе кодирования, давайте рассмотрим оптимальные способы их устранения.
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 .
Решение проблемы:
- Обновляйте библиотеки до последней стабильной версии.
- Изучите работу библиотеки и любые потенциальные проблемы с памятью.
- Настройте библиотеку в соответствии с рекомендациями и рекомендациями.
// Настройка EntityResolver public class CustomEntityResolver implements EntityResolver < // Реализация для разрешения сущностей >