Int a[ n ]; // ошибка, размер нельзя вычислить во время компиляции
int * p = new int[ n ]; // ок, используется значение во время выполнения
delete[] p;
}
Каждое динамическое выделение, помимо запрашиваемого пользовательского объема, расходует некоторый дополнительный объем служебных данных, размер которого сильно варьируется в зависимости от среды разработки, ее версии и конфигурации сборки. Например, Visual Studio 2010 в отладочной конфигурации дополнительно к запрашиваемой памяти выделяет еще 36 байт для внутренних нужд отладчика. Соответственно, при слишком малых объемах выделения удельный вес служебной памяти может превышать удельный вес полезной памяти.
Случайное повреждение служебной части динамически выделенной памяти также может привести к фатальному завершению программы, при этом обнаружить момент повреждения очень сложно, поскольку проблема обычно проявляется в момент освобождения памяти, что значительно позже момента повреждения.
При написании программ с повышенными требованиями к производительности к динамическому выделению памяти следует подходить очень внимательно. Обычно динамическое выделение памяти работает эффективнее для крупных блоков данных по сравнению с мелкими. Кроме того, выделение и освобождение памяти требует немалой порции времени, что может быть очень заметным в крупных программах. Временная доля для выделения+освобождения динамической памяти часто превышает 30% от общего времени выполнения.
Если память, которая более не используется программой, не освобождать, возникает явление утечки памяти (memory leak). Выделенный блок помечен распределителем динамической памяти как используемый, однако в программе не содержится ни одной переменной-указателя, хранящей его адрес, что делает его недоступным. В результате, блок никак не используется до завершения выполнения программы. Он не освобождается ни для других программ, ни для других блоков внутри данной программы.
int main ()
{
int * p = new int[ 10000000 ]; // Выделить выделили, а освобождать кто будет?
...
}
Для маленьких программ это явление возможно не имеет огромного значения, однако для больших программ, особенно для работающих в режиме 24x7, таких как веб-серверы, наличие значительного объема утечек памяти рано или поздно приводит к ее исчерпанию, а значит к последующему фатальному завершению.
Обнаружение утечек памяти является весьма нетривиальной задачей, требующей специальных инструментов для трассировки выделения и освобождения. Наилучшими методами предотвращения утечек памяти является аккуратность разработчика, а также применение “умных” указателей (std::unique_ptr, std::shared_ptr). Начинающих программистов, недостаточно аккуратно следящих за освобождением памяти, часто сравнивают с людьми, которые не моют за собой посуду после приема пищи - рано или поздно чистые тарелки заканчиваются.
При интенсивной работе с кучей, имеет место также более сложное явление фрагментации, когда распределитель памяти не может выделить цельный блок стоящий подряд, хотя имеется достаточное общее свободное пространство в виде нескольких меньших блоков.
В программах, сталкивающихся с такими сложностями, обычно реализовывают полностью собственную ручную логику распределения динамической памяти. Память выделяется крупными блоками, а алгоритм дальнейшего распределения оптимизируется под нужды конкретной задачи.
Дата добавления: 2016-01-29; просмотров: 1716;