Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.54/13: Рейтинг темы: голосов - 13, средняя оценка - 4.54
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700

Память освобождается, но значение остается

03.03.2016, 20:53. Показов 4071. Ответов 78
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Почему в следующем коде, программа завершается принудительно, но в консоли все равно видно значение переменной, память которой была удалена?
Откуда берется это значение?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int* getIntegerFromHeap()
{
    int *x = new int(20);
    return x;
}
 
int main()
{
    int *x = getIntegerFromHeap();
    cout << *x << std::endl;
    delete x;
    cout << *x;//выводит в консоль 20 и программа аварийно завершается 
    return 0;
}
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
03.03.2016, 20:53
Ответы с готовыми решениями:

Не освобождается память
Мне надо сделать прогу,точнее переделать, с использованием динамического двумерного массива... Я не буду писать эту прогу в изночальном...

Освобождается ли память?
Под вводимое с клавиатуры количество переменных выделяется память. Затем переменным в цикле присваивается значение. int units, *x; ...

Память освобождается не полностью
Суть такова. При многократном выделении/освобождении растет (судя по диспетчеру задач Шindows) используемая программой память. Например,...

78
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
03.03.2016, 22:58  [ТС]
Студворк — интернет-сервис помощи студентам
DrOffset,
Про физическое удаление ясное дело Не правильно выразился, имел ввиду освобождение памяти а не исчезновение куска микросхемы)
Цитата Сообщение от DrOffset Посмотреть сообщение
Если память вернули менеджеру памяти (пометили свободной), то утечки нет.
Но собеседник castaway говорит что значение хранится после delete. Если какой нибудь компилятор не отдаст этот адрес(как и происходит в некоторых тестах) по следующему запросу и значение все же хранится, то утечка есть, вот моя мысль. Но как я понял, заморачиваться не нужно. Хотелось докопаться до истины, думал есть стандартное поведение комиляторов на этот счет, оказалось нет.
Всем спасибо! Было очень интересно
0
93 / 6 / 5
Регистрация: 25.02.2016
Сообщений: 30
03.03.2016, 23:00
Цитата Сообщение от sys_beginner Посмотреть сообщение
Когда в памяти остаются данные, которые больше не используются.
Я ведь привел Вам код. После его выполнения Вы уже не получите доступ к своему указателю. Соответственно его состояние сможет изменить другая переменная.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
 
int* getIntegerFromHeap()
{
    int *x = new int(20);
    return x;
}
 
void f()
{
    int *x = getIntegerFromHeap();
    std::cout << *x << std::endl;
}
 
int main()
{
    f();
 
    std::cout << *x;
    // x не пренадлежит потоку
    return 0;
}
И уж если Вам совсем станет легче, то для основного потока например винда выделит стандартно 1 Мб в стековй памяти. Так что как не крути, 1 Мб всегда у вас будет, если не указать явно сколько выделить под стек.
0
Эксперт С++
4986 / 3093 / 456
Регистрация: 10.11.2010
Сообщений: 11,170
Записей в блоге: 10
03.03.2016, 23:02
Цитата Сообщение от sys_beginner Посмотреть сообщение
Но собеседник castaway говорит что значение хранится.
Собеседник говорит что значение по адресу хранится до тех пор, пока не будет перезаписано. Вы одновременно и не понимаете, и искажаете сказанное.
0
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
03.03.2016, 23:02
Цитата Сообщение от sys_beginner Посмотреть сообщение
То есть занимается лишнее пространство для данных которые не будут больше использованы.
Господи, ну память же не резиновая (пока опустим детали про подкачку и виртуальные адреса).
Главное - это не то, что в этих ячейках лежит, а можно ли получить эти ячейки для работы. Если получить можно, то памяти достаточно. Именно поэтому память не очищается (например не забивается нулями) в таких случаях - это бессмысленная работа. А утечка, говоря по-простому, - это когда память уже не нужна, но использовать ее никто не может, потому что свободной ее не пометили.
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
03.03.2016, 23:04  [ТС]
TheCalligrapher,
Большое спасибо! Но странно то, что нельзя в таких случаях обойтись каким нибудь сигналом для освобождения мелкого куска этого большого блока и соответствующего значения. Не спец, может на машинном уровне это действительно не оправданно и слишком ресурсозатратно
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13239 / 6871 / 1827
Регистрация: 18.10.2014
Сообщений: 17,417
03.03.2016, 23:05
Такой двухуровневый механизм реализуется именно потому, что запрос/освобождение памяти у ОС - операция тяжелая и выполнять ее для каждого маленького блока памяти - расточительно. Не говоря уже о том, что ОС может вообще не умет выделять маленькие блоки памяти.

Однако, если вы при помощи 'new' попробуете выделить достаточно большой блок памяти, то смысла в двухуровневом механизме не будет, и как правило запрос на память будет отправлен прямо в ОС. После освобождения такого блока, память будет возвращена обратно ОС, т.е. память станет свободной с точки зрения ОС. В результате попытка доступа к такой памяти будет приводить к срабатываниям механизмов защиты памяти в современных ОС. Например

C++
1
2
3
4
5
6
7
int main()
{
    int *x = new int[1000000]();
    std::cout << *x << std::endl;
    delete[] x;
    std::cout << *x << std::endl;
}
Под MSVC и Windows такой код падает.
1
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
03.03.2016, 23:08
Цитата Сообщение от sys_beginner Посмотреть сообщение
не отдаст этот адрес(как и происходит в некоторых тестах) по следующему запросу и значение все же хранится, то утечка есть, вот моя мысль.
Если эту память вернули менеджеру (пометили свободной), и он ее не отдал по следующему запросу - это не значит что произошла утечка. Это всего-лишь значит, что алгоритм выделения памяти так посчитал нужным сделать. Иными словами, раз не отдал этот адрес при N запросе, отдаст на N+1. Но тебя это не должно волновать. Твое дело вызывать delete тем адресам, которые возвращала new. Так ты гарантируешь, что никаких утечек у тебя не будет
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
03.03.2016, 23:12  [ТС]
Цитата Сообщение от BlackMare Посмотреть сообщение
После его выполнения Вы уже не получите доступ к своему указателю. Соответственно его состояние сможет изменить другая переменная.
Каким образом? Не имение возможности достучаться до указателя насколько мне известно не приводит к автоматическому освобождению выделенной памяти из кучи. Думаю delete все же нужен.

castaway,
Наверное мы просто не понимаем друг друга

Цитата Сообщение от DrOffset Посмотреть сообщение
Главное - это не то, что в этих ячейках лежит, а можно ли получить эти ячейки для работы. Если получить можно, то памяти достаточно.
Да, я не говорил про то что мы достигаем предела в этом случае А если это огромный объект и у меня на сервере есть многов других процессов, которым тоже нужна память? Условно говоря есть веб сервер который может получить тяжелый запрос, на выполнение которого потребуется много памяти. И потому что программа на С++ вовремя не избавилась от большого объекта, процесс веб сервера будет успешно завален. Тоже не честно
Думаю тебя себя изжила Многое от вас узнал коллеги! Спасибо каждому из вас!
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13239 / 6871 / 1827
Регистрация: 18.10.2014
Сообщений: 17,417
03.03.2016, 23:13
Цитата Сообщение от sys_beginner Посмотреть сообщение
для освобождения мелкого куска этого большого блока
Что такое "освобождения мелкого куска"? Современные ОС в принципе не умеют "освобождать мелкие куски". Например, Windows работает со страницами размера 4K. Все фундаментальные механизмы выделения, освобождения и защиты памяти работают с гранулярностью 4K. (И ноги у этого растут из аппаратной архитектуры.) Т.е. в Windows в принципе невозможно "выделить" или "освободить" одинокий 'int'. Поэтому освобождение одинокого 'int' возможно только на уровне библиотеки времени выполнения, т.е. путем "помечания" и "запоминания" некоторого участка памяти, как свободного, внутри большого блока, запрошенного у ОС.

Если быть совершенно точным, в самом Windows есть Heap API, который позволяет работать с маленькими блоками памяти и библиотеки времени выполнения активно используют этот API. Но это не принципиально, ибо суть тут в том, что Heap API - это тоже менеджер памяти второго уровня, работающий как описано выше. Т.е. мелкие блоки, освобожденные Heap API - это по-прежнему лишь маленькие регионы внутри большого блока, запрошенного у ОС. ОС не знает, что происходит внутри этого блока и никаких механизмов защиты памяти внутри блока предоставлять не может в принципе. Именно поэтому у вас получается доступиться к "освобожденной" памяти.
0
93 / 6 / 5
Регистрация: 25.02.2016
Сообщений: 30
03.03.2016, 23:15
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
что ОС может вообще не умет выделять маленькие блоки памяти.
Есть понятие гранулированность выделяемых блоков. Точно не помню, в Win для стека выделяются блоки адресов по 64К по моему, то есть даже для одного int выделится 64К (для х86)

Цитата Сообщение от sys_beginner Посмотреть сообщение
Каким образом?
я ведь написал, что это для конкретного случая. Так как для запуска Вашего приложения, ОС 100% выделит отдельное адресное пространство а потом его вернет. Или вы думаете, что можно вот так запросто выделить адреса внутри адресов, используемых ОС?
0
3 / 3 / 1
Регистрация: 03.03.2016
Сообщений: 86
03.03.2016, 23:20
Самый простой способ , без подключения библиотек-это cin.get();
После нажатия клавиши программа закроется.
0
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
03.03.2016, 23:21
Цитата Сообщение от sys_beginner Посмотреть сообщение
Условно говоря есть веб сервер который может получить тяжелый запрос, на выполнение которого потребуется много памяти. И потому что программа на С++ вовремя не избавилась от большого объекта, процесс веб сервера будет успешно завален. Тоже не честно
Честным будет писать программу так, чтобы она правильно расходовала свои ресурсы
Ну и в реальности скорее всего ничего не завалится, т.к. современные операционные системы не так просты и умеют сбрасывать давно неиспользуемые занятые участки памяти на диск, освобождая тем самым место для актуальных данных в озу.
Можно начать читать отсюда и отсюда.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13239 / 6871 / 1827
Регистрация: 18.10.2014
Сообщений: 17,417
03.03.2016, 23:29
Цитата Сообщение от sys_beginner Посмотреть сообщение
Условно говоря есть веб сервер который может получить тяжелый запрос, на выполнение которого потребуется много памяти. И потому что программа на С++ вовремя не избавилась от большого объекта, процесс веб сервера будет успешно завален.
Если такое произойдет, это будет лишь означать, что применяемая вашей библиотекой времени выполнения стратегия менеджмента динамической памяти является неоптимальной или даже соврешенно неприемлемой в рамках вашей конкретной задачи. Как вы сами понимаете, эта стратегия - это некая "средняя температура по больнице", попытка некоего компромисса, достигающего некоего среднего уровня оптимальности для всех случаев жизни.

Если вас она никак не устраивает, это означает, что заниматься менеджментом динамической памяти вам придется вручную, самому, а не полагаться на 'new'. Это совершенно нормально.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
03.03.2016, 23:42
Цитата Сообщение от sys_beginner Посмотреть сообщение
Когда в памяти остаются данные, которые больше не используются. То есть занимается лишнее пространство для данных которые не будут больше использованы.
работа с памятью на самом деле достаточно хитрая.
процессы не имеют прямого доступа к физической памяти.
вместо этого, они оперируют так называемыми "страницами виртуальной памяти".

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

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

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

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

когда встречается delete - соответственно, помечает свободным.
в будущем, по очередному запросу программы,
может заново его выдать.

таким образом, до тех пор, пока процесс не израсходовал весь запас
заранее отжатой у системы памяти,
он может свободно играццо в своей собственной песочнице.
и не думать о судьбе освобожденных кусочков.
1
93 / 6 / 5
Регистрация: 25.02.2016
Сообщений: 30
04.03.2016, 00:44
В продолжение отличного изложения материала hoggy, приложу карту памяти. Исходный код почти один в один как у ТС за небольшим исключением:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
 
int* getIntegerFromHeap() noexcept
{
    int *x = new int(20);
    return x;
}
 
void f() noexcept
{
    int *x = getIntegerFromHeap();
    std::cout << *x << std::endl;
    delete x;
}
 
int main()
{
    f();
 
    std::cin.get();
    return 0;
}
Ну и сама карта:
Миниатюры
Память освобождается, но значение остается  
0
Эксперт С++
4986 / 3093 / 456
Регистрация: 10.11.2010
Сообщений: 11,170
Записей в блоге: 10
04.03.2016, 18:43
Цитата Сообщение от hoggy Посмотреть сообщение
процессы не имеют прямого доступа к физической памяти.
вместо этого, они оперируют так называемыми "страницами виртуальной памяти".
Вот тут я бы поспорил... Виртуальное адресное пространство проецируется на физическое, т.е. обращаясь к определённому участку виртуальный памяти, мы по сути обращаемся к определённому участку физической памяти. Получается, что процесс имеет прямой доступ к физической памяти.
Другое дело, если вы имеете в виду доступ к определённым адресам физической памяти которые проецируются один в один, но и это утверждение не совсем верно без указания ОС, т.к. в защищённом режиме (если речь вообще идёт о x86 или x86_64) всё адресное пространство можно спроецировать один в один - виртуальное к физическому.
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
04.03.2016, 18:46
Цитата Сообщение от castaway Посмотреть сообщение
Виртуальное адресное пространство проецируется на физическое, т.е. обращаясь к определённому участку виртуальный памяти, мы по сути обращаемся к определённому участку физической памяти.
суть в том, что мы в принципе не знаем,
к чему именно мы обращаемся.

виртуальный слой полностью абстрагирует
процесс от "физической реальности".

физически, данные вообще могут оказаться на жестком диске,
а не в оперативной памяти, например.
1
Эксперт С++
4986 / 3093 / 456
Регистрация: 10.11.2010
Сообщений: 11,170
Записей в блоге: 10
04.03.2016, 18:59
Цитата Сообщение от hoggy Посмотреть сообщение
суть в том, что мы в принципе не знаем,
к чему именно мы обращаемся.
Да, в некоторых ОС мы знать этого не можем, но ведь это же не говорит о том что мы не имеем прямого доступа к физической памяти, если не учитывать "прослойку" виртуальности адресов. В конечном итоге мы обращаемся именно к физическому адресу.
Я понимаю что вы имеете в виду, просто такие щекотливые нюансы в таких темах следует уточнять.
1
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13239 / 6871 / 1827
Регистрация: 18.10.2014
Сообщений: 17,417
04.03.2016, 19:16
Цитата Сообщение от castaway Посмотреть сообщение
Получается, что процесс имеет прямой доступ к физической памяти.
Это не прямой доступ к физической памяти. Доступ получается именно опосредованный - через посредство механизма проекции виртуального адресного пространства на физическую память.
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
04.03.2016, 19:17
castaway, так ведь доступ к физ памяти означает означает отсуствие абстракции про страницы виртуальной памяти. Как по мне доступ не прямой, если приходится "переадресовывать"
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
04.03.2016, 19:17

Почему память массива не освобождается?
В выводе *b должна быть ересь, но на самом деле коректно выводит цифру &quot;3&quot;. #include &lt;iostream&gt; using namespace std; void...

Не освобождается память при выбросе исключений
это у меня находится в классе Add. Туда я добавляю элементы, перед этим проверяю, нет ли такого уже: try { ...

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

Не освобождается память в списке указателей на класс
#include &lt;iostream&gt; #include &lt;list&gt; using namespace std; class myClass{ private: int x; bool life; public: ...

Освобождается ли память выделенная под массив после вызова деструктора класса
Здравствуйте, изучаю ООП, вот у меня такой вопрос, вот мой код: #include &lt;iostream&gt; using namespace std; class myclass { ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Книги по геймдизайну, левел-дизайну, игровым механикам и проектированию игрового опыта
8Observer8 08.11.2026
Содержание блога | English Version 1. 2003 - 06 - Designing Virtual Worlds (1st Edition) Автор: Richard A. Bartle | Объем: 768 стр. Ссылки: Amazon . . .
Родители токсичные абьюзеры по отношению к своим детям ругают их оскорбляют не любят
zorxor 08.11.2026
Жить в атмосфере постоянных оскорблений, критики и холодности со стороны родителей — это тяжелое и болезненное испытание, которое оставляет глубокие эмоциональные раны. Токсичное и абьюзивное. . .
Как только я захожу к себе в свою комнату я сразу же с себя снимаю свои трусы. Ответ от Джемени ИИ.
zorxor 08.11.2026
Джемени, как только я захожу к себе в свою комнату я сразу же с себя снимаю свои трусы. Многие люди, возвращаясь домой, сразу переодеваются в максимально свободную одежду или вовсе предпочитают. . .
Паттерн очереди действий/команд (Action / Command Queue). Система очереди действий и кат-сцен с SDL3 Callbacks, cglm и OpenGL
8Observer8 07.11.2026
Содержание блога | English Version Руководство для начинающих по реализации паттерна очереди действий/ команд (Action / Command Queue) на C++ (C++20) с использованием официального SDL3 Callbacks. . .
Проверка полного ФИО в типовом справочнике
Maks 07.11.2026
Решение реализовано в конфигурации КА2, на примере справочника "КонтактныеЛицаПартнеров". Задача: Запрет инициалов. Не допускаеть использование сокращений вида "И. И. ", "И. И. ", "И И" и. . .
Про "Windows must die!"
kumehtar 04.11.2026
Знаете, чет накатило. . . . Когда-то это было почти боевым кличем: мол, нормальный человек сидит на DOS, OS/ 2 или Linux, а вот это вот - Must Die. А теперь человек произносит «мастдай» с усмешкой - и. . .
Красочные поля с номером страницы svg+background-image
russiannick 04.11.2026
Красочные поля с номером страницы не менее важны чем в эпоху бумажных книг. Посему спешу представить почтеннейшей публике этот важный инструмент который эти поля и формирует. В процессе разработки. . .
Вступаем в новую фазу генерации favicons, векторную.
russiannick 02.11.2026
Теперь нет нужды скрывать что используется простой svg. Исходный код изображения помещаем в поле и жмем кнопку. Исходник преобразуется в вид корректный для помещения в favicon или в url(). Нажатие. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru