Вызывает ли утечка памяти при выгрузке библиотеки DLL утечку в хост-процессе? - PullRequest
8 голосов
/ 25 сентября 2008

Рассмотрим этот случай:

dll = LoadDLL()
dll->do()

...
void do() {
    char *a = malloc(1024);
}
...

UnloadDLL(dll);

На этом этапе 1k, выделенный при вызове malloc (), снова будет доступен хост-процессу? DLL статически связывается с CRT.

Ответы [ 6 ]

8 голосов
/ 25 сентября 2008
  1. Память, используемая процессом, отслеживаемым ОС, применима ко всему процессу и не относится к DLL.

  2. Память отводится программе порциями ОС, называемой кучами

  3. Менеджеры кучи (malloc / new и т. Д.) Дополнительно разделяют порции и раздают их запрашивающему коду.

  4. Только при выделении новой кучи ОС обнаруживает увеличение памяти.

  5. Когда DLL статически связана с библиотекой времени выполнения C (CRT), частная копия CRT с функциями CRT, которые вызывает код DLL, компилируется и помещается в двоичный файл DLL. Malloc также включен в это.

  6. Эта закрытая копия malloc будет вызываться всякий раз, когда код, находящийся внутри статически связанной DLL, пытается выделить память.

  7. Следовательно, частная куча, видимая только для этой копии malloc, извлекается из ОС этим malloc, и она выделяет память, запрошенную кодом в этой частной куче.

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

  9. Однако если DLL динамически связана, память выделяется одной общей версией malloc, глобальной для всего кода, который связан в режиме совместного использования.

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

Редактировать - добавлены описания сценария связывания.

5 голосов
/ 25 сентября 2008

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

Проблема с ЭЛТ, которая протекает, конечно, в том, что она протекает. Проблема с CRT, который не протекает, заключается в том, что исполняемый файл может разумно ожидать использования памяти, так как память, размещенная в malloc, должна оставаться пригодной для использования до вызова free.

3 голосов
/ 12 апреля 2010

На самом деле помеченный ответ неверный. Это право есть утечка. В то время как технически выполнимо для каждой dll реализовать собственную кучу и освободить ее при завершении работы, большинство «динамических» куч - статических или динамических - являются обертками вокруг API кучи процессов Win32.

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

3 голосов
/ 25 сентября 2008

из MSDN Потенциальные ошибки при прохождении объектов CRT через границы DLL

Каждая копия библиотеки CRT имеет отдельное и отличное состояние. В качестве таких, Объекты CRT, такие как дескрипторы файлов, переменные среды и локали действителен только для копии ЭЛТ где эти объекты расположены или задавать. Когда DLL и ее пользователи используют разные копии библиотеки CRT, Вы не можете передать эти объекты CRT через границу DLL и ожидать их правильно подобрать на другая сторона.

Кроме того, потому что каждая копия ЭЛТ библиотека имеет свой собственный менеджер кучи, выделение памяти в одной библиотеке CRT и передача указателя через DLL граница должна быть освобождена другим копия библиотеки ЭЛТ является потенциальной причина повреждения кучи.

Надеюсь, это поможет.

1 голос
/ 25 сентября 2008

Можно сделать тест и посмотреть, есть ли утечки памяти. Вы запускаете простой тест 30 раз, выделяя 1 МБ каждый раз. Вы должны понять это довольно быстро.

Одно можно сказать наверняка. Если вы выделили память в DLL, вы также должны освободить эту память там (в DLL).

Например, у вас должно быть что-то вроде этого (простой, но интуитивно понятный псевдокод):

dll = DllLoad();

ptr = dll->alloc();

dll->free(ptr);

DllUnload(dll);

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

0 голосов
/ 25 сентября 2008

Нет, вы не протекаете.

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

Это означает, что куча, созданная статически связанным CRT, не является той же кучей, что и CRT другого dll.

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

...