Немного расскажу про дебажную кучу, речь пойдет о Visual Studio 2008. В остальных версиях дебажная куча выглядит примерно так же. Про другие компиляторы не знаю.
Основная мысль - дебажная куча отличается от релизной, чтобы облегчить отладку. И, если в дебаге произойдет порча памяти, то ее можно отловить. Visual Studio выдает в таком случае окно с сообщением и пишет в Output что-то вроде
Heap corruption at address.
HEAP[MyProg.exe]: Heap block at 0AC6A400 modified at 0AC6A6EC
past requested size of 2e4Итак, в чем состоят отличия и каким образом отлавливаются ошибки. Давайте я пример приведу, с примером удобнее.
class CBase
{
public:
int BaseI;
int BaseJ;
};
class CDerived : public CBase
{
public:
int DerivedI;
};
int main()
{
CBase *pBase = new CBase;//(1)
pBase->BaseI = 3;
pBase->BaseJ = 4;//(2)
delete pBase;//(3)
return 0;
}Как будет выглядеть память в точке (1). (Чтобы вывести окно с памятью, выберите Debug->Windows->Memory->Memory1).
0x00984ED8 cd cd cd cd cd cd cd cd fd fd fd fd 00 00 00 00 У меня экземпляр класса CBase расположился по адресу 0x00984ED8. Оба int'а, а это восемь байт, заполнены значением 0xCD, Clean Memory. Это значение по умолчанию.
Дальше четыре байта 0XFD, Fence Memory, она же "no mans land". Это такой заборчик, которым обрамляется свежевыделенная память. Перед адресом 0x00984ED8 стоят точно такие же четыре байта.
Точка (2).
0x00984ED8 03 00 00 00 04 00 00 00 fd fd fd fd 00 00 00 00Мы записали значения 3 и 4 и они идут одно за другим. Младший байт идет первым, потому что я работают с little endian платформой.
Точка (3)
0x00984ED8 dd dd dd dd dd dd dd dd dd dd dd dd 00 00 00 00Память после удаления заполняется значениями 0xDD, Dead Memory. После вызова функции HeapFree() будет заполнена значениями 0xFEEEFEEE.
Давайте теперь сымитируем багу и посмотрим как Visual Studio ее поймает. Это реальная бага, я ее упростила до синтетического примера. На самом деле кода было больше и он был размазан по нескольким функциям.
CBase *pBase = new CBase;//(1)
pBase->BaseI = 3;
pBase->BaseJ = 4;//(2)
CDerived* pDerived = static_cast<CDerived*>(pBase);
pDerived->DerivedI = 7;//(3)
delete pBase;
Итак, мы стали приводить по иерархии с помощью static_cast'а, вместо dynamic_cast'а. Что в итоге получили. В точках (1) и (2) программа выглядит все также. В точке (3) мы полезли в чужую память и затерли забор.
03 00 00 00 04 00 00 00 07 00 00 00 00 00 00 00После попытки вызвать delete pBase мы получим сообщение об ошибке, потому что забора нет, а это означает, что мы лазили в чужую память.
HEAP CORRUPTION DETECTED: after Normal block (#68) at 0x008D4ED8.
CRT detected that the application wrote to memory after end of heap buffer.Еще различия между дебажной и релизной кучами приводят к тому, что программа начинает себя вести по-разному в дебаге и в релизе. Простой пример - дебажная "падает", релизная нет. Очень может быть, что "падение" - это не падение вовсе, а как раз сообщение о порче памяти. Почитайте повнимательнее, что там в окне написано.
Также народ жалуется, что дебажная версия работает сильно меденнее релизной. Причиной этого в том числе может быть дебажная куча. В интернетах пишут, что можно ее в дебаге отключить то ли с помощью переменной окружения _NO_DEBUG_HEAP, то ли NO_DEBUG_HEAP, в единицу ее надо выставить. Я пробовала ее отключить, куча осталась дебажной.
Ссылки по теме:
Win32 Debug CRT Heap Internals
Inside CRT: Debug Heap Management
Memory Management and the Debug Heap (MSDN)
Приведение типов в C++






Atom feed