Распределение памяти кучи

Если я распределяю память динамически в своей программе с помощью malloc(), но я не освобождаю память во время выполнения программы, освобождается ли динамически выделенная память после завершения программы?

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

Примечание: один ответ, о котором я мог подумать, - это перезагрузка машины, на которой я выполняю программу. Но если я выполняю программу на удаленном компьютере, и перезагрузка не является вариантом?

Ответы

Ответ 1

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


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

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

Я предполагаю, что причина в том, что операционная система должна быть способна изящно обрабатывать нерегулярные ситуации:

  • вредоносных программ (например, тех, которые не освобождают их память намеренно, в надежде повлиять на систему, в которой они работают)
  • аномальные окончания программ (например, ситуации, когда программа неожиданно заканчивается и, следовательно, может не иметь возможности явно указывать free ее динамически выделенную память)

Любая операционная система, которой стоит ее соль, должна иметь дело с такими ситуациями. Он должен изолировать другие части системы (например, сам и другие запущенные процессы) от неисправного процесса. Если это не так, в систему будет распространяться утечка памяти. Это означает, что ОС будет утечка памяти (которая обычно считается ошибкой).

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

Ответ 2

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

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

Ответ 3

Даже если ваша ОС выполняет очистку на exit(). Вывод syscall для выхода часто завершается функцией exit(). Вот какой-то псевдокод, полученный от изучения нескольких реализаций libc, чтобы продемонстрировать, что происходит вокруг main(), что может вызвать проблему.

//unfortunately gcc has no builtin for stack pointer, so we use assembly
#ifdef __x86_64__
   #define STACK_POINTER "rsp"
#elif defined __i386__
   #define STACK_POINTER "esp"
#elif defined __aarch64__
   #define STACK_POINTER "x13"
#elif defined __arm__
   #define STACK_POINTER "r13"
#else
  #define STACK_POINTER "sp" //most commonly used name on other arches
#endif
char **environ;
void exit(int);
int main(int,char**,char**); 
_Noreturn void _start(void){ 
   register long *sp __asm__( STACK_POINTER ); 
   //if you don't use argc, argv or envp/environ, just remove them
   long argc = *sp;
   char **argv = (char **)(sp + 1);
   environ = (char **)(sp + argc + 1);
   //init routines for threads, dynamic linker, etc... go here
   exit(main((int)argc, argv, environ));
   __builtin_unreachable(); //or for(;;); to shut up compiler warnings
}

Обратите внимание, что exit вызывается с использованием возвращаемого значения main. При статической сборке без динамического компоновщика или потоков exit() может быть непосредственно встроенным syscall(__NR_exit,main(...)); однако если ваш libc использует обертку для exit(), которая выполняет подпрограммы *_fini() (большинство реализаций libc), есть еще одна функция для вызова после завершения main().

Вредоносная программа может LD_PRELOAD exit() или любая из подпрограмм, которые она вызывает, и превратить ее в своего рода зомби-процесс, который никогда не освободит память.

Даже если вы выполняете free() до exit(), процесс по-прежнему будет потреблять некоторую память (в основном размер исполняемого файла и до некоторой степени общие библиотеки, которые не используются другими процессами), но некоторые операционные системы могут повторно использовать память не malloc() ed для последующих нагрузок той же самой программы, чтобы вы могли работать в течение нескольких месяцев, не замечая зомби.

FWIW, большинство реализаций libc имеют некоторую оболочку exit(), за исключением dietlibc (при построении как статическую библиотеку) и мой частичный, только статический libc.h, который я только разместил на Puppy Linux Форум.

Ответ 4

Как мы говорим, мозг операционной системы - это ядро. Операционная система имеет несколько обязанностей.

Управление памятью - это функция ядра.

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

Часто первым шагом в этом является виртуальная адресация, обычно достигаемая пейджинговой и/или сегментацией. Виртуальная адресация позволяет ядру сделать данный физический адрес другим адресом - виртуальным адресом. Виртуальные адресные пространства могут отличаться для разных процессов; память, которую один процесс обращается на конкретном (виртуальном) адресе, может быть другой памятью, с которой другой процесс обращается по тому же адресу.

Это позволяет каждой программе вести себя так, как будто она единственная (отдельно из ядра) и, таким образом, предотвращает сбои приложений друг друга


Распределение памяти

таНос

Выделить блок памяти из кучи

..NET Эквивалент: Не применимо. Чтобы вызвать стандартную функцию C, используйте PInvoke.


Куча

Куча - это область памяти вашего компьютера, которая не управляется автоматически для вас и не так сильно управляется процессором. это более свободно плавающая область памяти (и больше). Выделить памяти в куче, вы должны использовать malloc() или calloc(), которые встроенные функции C. Как только вы выделили память в кучу, вы несут ответственность за использование free() для освобождения этой памяти после того, как вы больше не нужны. Если вы этого не сделаете, ваша программа будет что называется утечкой памяти . То есть, память в куче будет (и не будут доступны другим процессам).


Утечка памяти

Для Windows

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

Предотвращение утечек памяти в приложениях Windows

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

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

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

. Вот несколько примеров общих шаблонов распределения:

  • Память кучи через функцию HeapAlloc или ее время выполнения C/С++ эквиваленты malloc или new

  • Прямые выделения из операционной системы через VirtualAlloc функция.

  • Ручки ядра, созданные с помощью API Kernel32, например CreateFile, CreateEvent или CreateThread, хранить память ядра от имени приложение

  • Ручки GDI и USER, созданные с помощью API-интерфейсов User32 и Gdi32 (по умолчанию, каждый процесс имеет квоту в 10 000 дескрипторов)

Для Linux

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

Ответ 5

Если я распределяю память динамически в своей программе, используя malloc(), но я не освобождать память во время выполнения программы, будет динамически выделенная память освобождается после завершения программы?

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

Это намного сложнее, чем ваш вопрос заставляет его звучать, поскольку физическая память, используемая процессом, может быть записана на диск (выгружен). Но с Windows, Unix (Linux, MAC OS X, iOS, android) система освободит ресурсы, которые она передала процессу.

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

Каждый запуск программы получает новый набор памяти. Это берется из системы и предоставляется как виртуальные адреса. Современные операционные системы используют функцию адрес-пространство-макет-рандомизацию (ASLR) как функцию безопасности, это означает, что куча должна предоставлять уникальные адреса каждый раз, когда запускается ваша программа. Но по мере того, как ресурсы других прогонов были убраны, нет необходимости освобождать эту память.

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

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

Не освобождая память программы при ее выполнении, она "будет работать" в Windows и Unix и, возможно, в любой другой разумной операционной системе.

Преимущества освобождения памяти

Операционная система хранит список больших блоков памяти, выделенных для процесса, а также библиотека malloc хранит таблицы небольших фрагментов памяти, выделенных для malloc.

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

Недостатки освобождения памяти

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

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

Несколько раз в моей карьере я преобразовал процесс в общий объект /dll. Это были проблематичные преобразования, из-за утечек, которые, как ожидалось, были обработаны завершением процесса ОС, начали выживать за пределами жизни "основного".

Ответ 6

Память, выделяемая malloc, должна быть освобождена программой распределения. Если нет и память не будет распределена, то придет одно очко, что программа закончится с допустимого распределения памяти и выбросит ошибку сегментации или из памяти, Каждый набор распределения памяти по malloc должен сопровождаться бесплатным.