Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
Undisputed
712 / 319 / 68
Регистрация: 10.06.2014
Сообщений: 2,268
Завершенные тесты: 3
1

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

03.03.2016, 20:53. Просмотров 1619. Ответов 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
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
03.03.2016, 20:53
Ответы с готовыми решениями:

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

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

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

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

78
Undisputed
712 / 319 / 68
Регистрация: 10.06.2014
Сообщений: 2,268
Завершенные тесты: 3
03.03.2016, 22:58  [ТС] 41
DrOffset,
Про физическое удаление ясное дело Не правильно выразился, имел ввиду освобождение памяти а не исчезновение куска микросхемы)
Цитата Сообщение от DrOffset Посмотреть сообщение
Если память вернули менеджеру памяти (пометили свободной), то утечки нет.
Но собеседник castaway говорит что значение хранится после delete. Если какой нибудь компилятор не отдаст этот адрес(как и происходит в некоторых тестах) по следующему запросу и значение все же хранится, то утечка есть, вот моя мысль. Но как я понял, заморачиваться не нужно. Хотелось докопаться до истины, думал есть стандартное поведение комиляторов на этот счет, оказалось нет.
Всем спасибо! Было очень интересно
0
BlackMare
93 / 6 / 5
Регистрация: 25.02.2016
Сообщений: 30
03.03.2016, 23:00 42
Цитата Сообщение от 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
castaway
Эксперт С++
4953 / 3059 / 456
Регистрация: 10.11.2010
Сообщений: 11,151
Записей в блоге: 10
Завершенные тесты: 1
03.03.2016, 23:02 43
Цитата Сообщение от sys_beginner Посмотреть сообщение
Но собеседник castaway говорит что значение хранится.
Собеседник говорит что значение по адресу хранится до тех пор, пока не будет перезаписано. Вы одновременно и не понимаете, и искажаете сказанное.
0
DrOffset
11898 / 6450 / 1547
Регистрация: 30.01.2014
Сообщений: 10,508
03.03.2016, 23:02 44
Цитата Сообщение от sys_beginner Посмотреть сообщение
То есть занимается лишнее пространство для данных которые не будут больше использованы.
Господи, ну память же не резиновая (пока опустим детали про подкачку и виртуальные адреса).
Главное - это не то, что в этих ячейках лежит, а можно ли получить эти ячейки для работы. Если получить можно, то памяти достаточно. Именно поэтому память не очищается (например не забивается нулями) в таких случаях - это бессмысленная работа. А утечка, говоря по-простому, - это когда память уже не нужна, но использовать ее никто не может, потому что свободной ее не пометили.
0
Undisputed
712 / 319 / 68
Регистрация: 10.06.2014
Сообщений: 2,268
Завершенные тесты: 3
03.03.2016, 23:04  [ТС] 45
TheCalligrapher,
Большое спасибо! Но странно то, что нельзя в таких случаях обойтись каким нибудь сигналом для освобождения мелкого куска этого большого блока и соответствующего значения. Не спец, может на машинном уровне это действительно не оправданно и слишком ресурсозатратно
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
6318 / 3070 / 830
Регистрация: 18.10.2014
Сообщений: 5,753
03.03.2016, 23:05 46
Такой двухуровневый механизм реализуется именно потому, что запрос/освобождение памяти у ОС - операция тяжелая и выполнять ее для каждого маленького блока памяти - расточительно. Не говоря уже о том, что ОС может вообще не умет выделять маленькие блоки памяти.

Однако, если вы при помощи '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
DrOffset
11898 / 6450 / 1547
Регистрация: 30.01.2014
Сообщений: 10,508
03.03.2016, 23:08 47
Цитата Сообщение от sys_beginner Посмотреть сообщение
не отдаст этот адрес(как и происходит в некоторых тестах) по следующему запросу и значение все же хранится, то утечка есть, вот моя мысль.
Если эту память вернули менеджеру (пометили свободной), и он ее не отдал по следующему запросу - это не значит что произошла утечка. Это всего-лишь значит, что алгоритм выделения памяти так посчитал нужным сделать. Иными словами, раз не отдал этот адрес при N запросе, отдаст на N+1. Но тебя это не должно волновать. Твое дело вызывать delete тем адресам, которые возвращала new. Так ты гарантируешь, что никаких утечек у тебя не будет
0
Undisputed
712 / 319 / 68
Регистрация: 10.06.2014
Сообщений: 2,268
Завершенные тесты: 3
03.03.2016, 23:12  [ТС] 48
Цитата Сообщение от BlackMare Посмотреть сообщение
После его выполнения Вы уже не получите доступ к своему указателю. Соответственно его состояние сможет изменить другая переменная.
Каким образом? Не имение возможности достучаться до указателя насколько мне известно не приводит к автоматическому освобождению выделенной памяти из кучи. Думаю delete все же нужен.

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

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

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

Цитата Сообщение от sys_beginner Посмотреть сообщение
Каким образом?
я ведь написал, что это для конкретного случая. Так как для запуска Вашего приложения, ОС 100% выделит отдельное адресное пространство а потом его вернет. Или вы думаете, что можно вот так запросто выделить адреса внутри адресов, используемых ОС?
0
Леонид1300
3 / 3 / 1
Регистрация: 03.03.2016
Сообщений: 86
03.03.2016, 23:20 51
Самый простой способ , без подключения библиотек-это cin.get();
После нажатия клавиши программа закроется.
0
DrOffset
11898 / 6450 / 1547
Регистрация: 30.01.2014
Сообщений: 10,508
03.03.2016, 23:21 52
Цитата Сообщение от sys_beginner Посмотреть сообщение
Условно говоря есть веб сервер который может получить тяжелый запрос, на выполнение которого потребуется много памяти. И потому что программа на С++ вовремя не избавилась от большого объекта, процесс веб сервера будет успешно завален. Тоже не честно
Честным будет писать программу так, чтобы она правильно расходовала свои ресурсы
Ну и в реальности скорее всего ничего не завалится, т.к. современные операционные системы не так просты и умеют сбрасывать давно неиспользуемые занятые участки памяти на диск, освобождая тем самым место для актуальных данных в озу.
Можно начать читать отсюда и отсюда.
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
6318 / 3070 / 830
Регистрация: 18.10.2014
Сообщений: 5,753
03.03.2016, 23:29 53
Цитата Сообщение от sys_beginner Посмотреть сообщение
Условно говоря есть веб сервер который может получить тяжелый запрос, на выполнение которого потребуется много памяти. И потому что программа на С++ вовремя не избавилась от большого объекта, процесс веб сервера будет успешно завален.
Если такое произойдет, это будет лишь означать, что применяемая вашей библиотекой времени выполнения стратегия менеджмента динамической памяти является неоптимальной или даже соврешенно неприемлемой в рамках вашей конкретной задачи. Как вы сами понимаете, эта стратегия - это некая "средняя температура по больнице", попытка некоего компромисса, достигающего некоего среднего уровня оптимальности для всех случаев жизни.

Если вас она никак не устраивает, это означает, что заниматься менеджментом динамической памяти вам придется вручную, самому, а не полагаться на 'new'. Это совершенно нормально.
0
hoggy
Эксперт С++
7813 / 3555 / 746
Регистрация: 15.11.2014
Сообщений: 8,113
Завершенные тесты: 1
03.03.2016, 23:42 54
Цитата Сообщение от sys_beginner Посмотреть сообщение
Когда в памяти остаются данные, которые больше не используются. То есть занимается лишнее пространство для данных которые не будут больше использованы.
работа с памятью на самом деле достаточно хитрая.
процессы не имеют прямого доступа к физической памяти.
вместо этого, они оперируют так называемыми "страницами виртуальной памяти".

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

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

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

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

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

таким образом, до тех пор, пока процесс не израсходовал весь запас
заранее отжатой у системы памяти,
он может свободно играццо в своей собственной песочнице.
и не думать о судьбе освобожденных кусочков.
1
BlackMare
93 / 6 / 5
Регистрация: 25.02.2016
Сообщений: 30
04.03.2016, 00:44 55
В продолжение отличного изложения материала 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
Миниатюры
Память освобождается, но значение остается  
castaway
Эксперт С++
4953 / 3059 / 456
Регистрация: 10.11.2010
Сообщений: 11,151
Записей в блоге: 10
Завершенные тесты: 1
04.03.2016, 18:43 56
Цитата Сообщение от hoggy Посмотреть сообщение
процессы не имеют прямого доступа к физической памяти.
вместо этого, они оперируют так называемыми "страницами виртуальной памяти".
Вот тут я бы поспорил... Виртуальное адресное пространство проецируется на физическое, т.е. обращаясь к определённому участку виртуальный памяти, мы по сути обращаемся к определённому участку физической памяти. Получается, что процесс имеет прямой доступ к физической памяти.
Другое дело, если вы имеете в виду доступ к определённым адресам физической памяти которые проецируются один в один, но и это утверждение не совсем верно без указания ОС, т.к. в защищённом режиме (если речь вообще идёт о x86 или x86_64) всё адресное пространство можно спроецировать один в один - виртуальное к физическому.
1
hoggy
Эксперт С++
7813 / 3555 / 746
Регистрация: 15.11.2014
Сообщений: 8,113
Завершенные тесты: 1
04.03.2016, 18:46 57
Цитата Сообщение от castaway Посмотреть сообщение
Виртуальное адресное пространство проецируется на физическое, т.е. обращаясь к определённому участку виртуальный памяти, мы по сути обращаемся к определённому участку физической памяти.
суть в том, что мы в принципе не знаем,
к чему именно мы обращаемся.

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

физически, данные вообще могут оказаться на жестком диске,
а не в оперативной памяти, например.
1
castaway
Эксперт С++
4953 / 3059 / 456
Регистрация: 10.11.2010
Сообщений: 11,151
Записей в блоге: 10
Завершенные тесты: 1
04.03.2016, 18:59 58
Цитата Сообщение от hoggy Посмотреть сообщение
суть в том, что мы в принципе не знаем,
к чему именно мы обращаемся.
Да, в некоторых ОС мы знать этого не можем, но ведь это же не говорит о том что мы не имеем прямого доступа к физической памяти, если не учитывать "прослойку" виртуальности адресов. В конечном итоге мы обращаемся именно к физическому адресу.
Я понимаю что вы имеете в виду, просто такие щекотливые нюансы в таких темах следует уточнять.
1
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
6318 / 3070 / 830
Регистрация: 18.10.2014
Сообщений: 5,753
04.03.2016, 19:16 59
Цитата Сообщение от castaway Посмотреть сообщение
Получается, что процесс имеет прямой доступ к физической памяти.
Это не прямой доступ к физической памяти. Доступ получается именно опосредованный - через посредство механизма проекции виртуального адресного пространства на физическую память.
0
rikimaru2013
2527 / 1187 / 357
Регистрация: 30.11.2013
Сообщений: 3,817
04.03.2016, 19:17 60
castaway, так ведь доступ к физ памяти означает означает отсуствие абстракции про страницы виртуальной памяти. Как по мне доступ не прямой, если приходится "переадресовывать"
0
04.03.2016, 19:17
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.03.2016, 19:17

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.