У меня всегда было впечатление, что попытка получить доступ к динамически освобожденной (сначала выделенной, а затем удаленной / освобожденной) памяти приведет к созданию coredump.
Однако, когда я выполнил приведенный ниже код, он прошел успешно.
int* ptr = new int(3);
delete ptr;
cout << "value : " << *ptr << " " << ptr;
Поэтому я пошел вперед и создал висячий указатель и явно попытался получить доступ к памяти, но теперь он был сброшен.
int* aptr;
aptr = (int*)0x561778;
cout << "value : " << *aptr << " " << aptr;
1) Если мы не можем получить доступ к памяти за пределами заданного пространства процесса, то как я смог получить доступ к памяти после того, как освободил / освободил ее? (Первый пример)
Кроме того, если это так, то как антивирус сканирует память, выделенную другими процессами?
2) Если я динамически выделяю, но не освобождаю память, это может привести к утечке памяти.
Но что, если весь мой процесс был убит? или завершил выполнение, так что закрыли.
Тогда не гарантирует ли ОС очистку всех ресурсов, выделенных для этого процесса? Так будет ли утечка памяти происходить только для процессов, которые находятся в долгосрочной перспективе?
Если это так, то когда я явно пытаюсь получить доступ к содержимому другого процесса, как ОС может гарантировать, что она не освободит эту память?
1) Если мы не можем получить доступ к памяти за пределами данного пространства процесса, то как
я смог получить доступ к памяти после того, как освободил / выпустил ее?
(Первый пример)
Поскольку среда выполнения C или C ++ хранит «кучу» памяти, а когда вы вызываете free или delete, память фактически не представляется непригодной для процесса, она просто помещается обратно в область «свободной памяти» кучи, поэтому это будет использовано повторно. Это сделано потому, что процесс очень часто выделяет некоторую память, освобождает ее, выделяет снова, освобождает и т. Д. Например,
void readfile(const std::string& fname)
{
std::ifstream f(fname.c_str());
std::string* content = new std::string;
while(cin.getline(content))
{
...
}
delete content;
}
Эта функция (тупо, потому что мы не должны выделять std::string
) сначала выделит место для std::string
, а затем место для содержимого [возможно, в нескольких частях] внутри std:string
когда getline
вызов читает файл. Там могут быть другие выделения памяти, например, в `std::ifstream
тоже.
Куча предназначена для минимизации количества обращений к ОС за отображением / удалением памяти из глобальной физической памяти в конкретный процесс, поскольку с точки зрения производительности достаточно «дорого» сопоставление и отключение виртуальной памяти практически на всех процессорах ( в частности, выгрузка уже не функционирующих страниц памяти из других ядер потребует отправки сообщения другому процессору, когда другой процессор прекратит работу в данный момент, обновит свои виртуальные отображения, а затем ответит «Я сделал это», прежде чем продолжить где это было). И, конечно, если ОС не отображает память процесса, когда процесс прекращает его использовать, этот же процесс действительно может «использовать» этот адрес памяти для поиска содержимого других процессов — что было бы плохо, поэтому ОС заставит все процессорные ядра отказаться от своих отображений памяти, прежде чем этот бит памяти можно будет снова использовать для другого процесса [по крайней мере].
Изменить: чтобы уточнить, куча иногда освобождает память обратно в ОС. Например, если вы делаете БОЛЬШОЕ выделение, а затем освобождаете это же выделение, оно может сразу же отобразить это, и, таким образом, вы не сможете получить доступ к памяти после ее освобождения. Любой доступ к памяти после того, как она была освобождена, является неопределенным поведением, среда выполнения может (и довольно часто будет) делать все, что ей нравится, с памятью в этот момент. Наиболее распространенные сценарии:
Одна и та же ОС может в разное время использовать любой из этих сценариев практически в любом порядке.
Кроме того, если это так, то как антивирус сканирует память?
выделены другими процессами?
Совершенно другой вопрос. Они используют либо интерфейсы отладки для чтения памяти другого процесса, либо свои собственные функции драйвера ядра, которые используют функции ядра, которые позволяют любому процессу читать память любого другого процесса — в конце концов, ядро может делать все что угодно. [На самом деле, довольно часто антивирусное программное обеспечение больше интересуется тем, что загружается в память из файла, поэтому применяйте фильтры доступа к файлам, которые проверяют чтение / запись данных в / из файлов, а не сканируют то, что находится в памяти]
2) Если я динамически распределяю, но не освобождаю память, то это
вызвать утечку памяти. Но что, если весь мой процесс был убит? или же
завершено исполнение, так что закрыли. Тогда ОС не гарантирует чистоту
все ресурсы, выделенные на этот процесс? Так бы утечка памяти
происходят только для процессов, которые в долгосрочной перспективе?
Память процесса освобождается, когда процесс умирает. Всегда, каждый раз. Или вы можете вызвать сбой системы, запустив процесс, который выделяет достаточное количество памяти, намеренно уничтожает ее, запускает ее снова, уничтожает, запускает, уничтожает и т. Д. Это было бы плохо, верно?
Конечно, у вас может быть очень быстрая утечка памяти. Пытаться:
std:string str;
str.append(100000, 'x');
std::vector<std::string> v;
int i = 0;
while(1)
{
std::cout << "i=" << i << std::endl;
v.push_back(str);
Пройдет не так много секунд, прежде чем система начнет переключаться, а через некоторое время она будет убита (если вам не надоест и сначала ее не убьют). Ожидайте, что система Linux станет довольно безразличной, если вы сделаете это …
Если это правда, то когда я явно пытаюсь получить доступ к содержимому
другой процесс, как ОС может гарантировать, что она не освобождает это
объем памяти?
Обычный процесс не сможет получить доступ к памяти, принадлежащей другому процессу — только через ограниченные интерфейсы, такие как интерфейсы отладки или специально написанные драйверы ядра, вы можете сделать это. Или с помощью поддерживаемой ОС разделяемой памяти, где одна и та же память отображается в два разных процесса с разрешения ОС, конечно.
Эти методы доступа к памяти другого процесса будут включать некоторую форму «подсчета ссылок» [на самом деле то же самое применимо, например, если процесс в данный момент находится в системном вызове, пытающемся сохранить файл размером 1000 МБ, и процесс по той или иной причине убит — скажем, другой поток вызывает неисправимую ошибку] - ОС отслеживает количество «пользователей» данного фрагмента памяти, чтобы она не вытаскивала коврик из-под ног какого-либо процесса [или самого себя] ,
Других решений пока нет …