Вот моя программа
#include <vld.h>
using namespace std;
int main() {
int* p = new int(100);
}
Визуальный отчет по детектору утечки
Visual Leak Detector Version 2.3 installed.
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 1 at 0x00891B60: 4 bytes ----------
Call Stack:
c:\xxx\documents\visual studio 2010\projects\stl1\stl1\stl1.cpp (11): stl1.exe!main + 0x7 bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (555): stl1.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (371): stl1.exe!mainCRTStartup
0x76B7338A (File and line number not available): kernel32.dll!BaseThreadInitThunk + 0x12 bytes
0x774B97F2 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x63 bytes
0x774B97C5 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x36 bytes
Data:
64 00 00 00 d....... ........Visual Leak Detector detected 1 memory leak (40 bytes).
Largest number used: 40 bytes.
Total allocations: 40 bytes.
Visual Leak Detector is now exiting.
The program '[8992] stl1.exe: Native' has exited with code 0 (0x0).
Зачем 40 bytes
утечка памяти, это действительно должно было быть 4 bytes
,
Кто-нибудь может объяснить, что здесь происходит?
Во-первых, когда вы запрашиваете выделение 4 байта, высока вероятность того, что вы всегда получите больший блок (что безопасно, поскольку вы должны использовать только те 4 байта, о которых вы просили).
Зачем?
Размер размещения должен храниться где-то (подумайте о new X[count]
случай и delete[]
это должно позвонить count
раз деструктор X
Затем выделение кучи обычно выполняется путем рекурсивного фрагментации кучи, например Распределение друзей.
Это связано с тем, что вы хотите использовать как можно меньше служебных данных (то есть количество байтов, используемых для управления распределением, по сравнению с реально распределенными байтами). Вы должны помнить, используется какой-то блок памяти или нет.
Отладка может также добавить размер выделения. В Visual Studio функция malloc / free вставляет 4 байта перед возвращаемым указателем с «защитой памяти», как (0xDDDDDDDD
) и выделить еще 4 байта для другой защиты памяти после запрошенного размера. Когда вы вызываете malloc или free (косвенно, new и delete), код обработчика кучи проверяет защиту и утверждает, что они не были изменены. Если они есть, это останавливает вашу программу, чтобы вы могли видеть «вокруг» место, где была изменена память. IIRC, 0xCDCDCDCD
используется для заполнения выделенной области, 0xFEEEFEEE
используется для заполнения освобожденной области, но блок еще не возвращен в систему, и 0xDDDDDDDD
используются для границ.
Таким образом, кажется, что размер блока, который вы получаете, составляет 40 байт (может быть, больше), даже если вы используете только «4».
VLD не отслеживает ваш код, он перехватывает функции управления памятью (например, malloc/free
) и построить список каждого выделенного блока. Этот список анализируется для удаления элементов при их освобождении. По окончании, любой оставшийся предмет в списке.
Таким образом, полученный вызов malloc, вероятно, исходит от ::operator new
который увеличил запрошенный размер до 40 байтов, или, возможно, в VLD добавлен блок из 32 байтов для отслеживания «запроса на выделение».
Посмотрев на Исходный код VLD, в частности, функция vldnew, она выделяет заголовок для каждого выделения:
vldblockheader_t *header = (vldblockheader_t*)RtlAllocateHeap(g_vldHeap, 0x0, size + sizeof(vldblockheader_t))
Скорее всего, vldblockheader_t
36 байтов в вашем случае.
Почему утечка памяти 40 байтов, это действительно должно быть 4 байта.
Это связано как с дополнительной информацией о динамически размещаемом объекте, так и с эффективным1, 2 управление динамической (кучной) памятью.
Что касается первого, то должна быть доступная информация, чтобы выделенная память кучи освобождалась после окончания срока службы объекта.
Что касается последнего, есть что-то под названием вместимость и он не обязательно должен быть равен выделенному размеру. Он может быть равным или большим, с дополнительным пространством, позволяющим приспособиться к росту без необходимости перераспределения при каждой вставке.
Обратите внимание, что в вашем случае эта емкость не предполагает ограничение размера шрифта. int
,
vector
s — это контейнеры последовательности, представляющие массивы, которые могут меняться в размере. Внутренне, векторы используют динамически распределенный массив для хранения своих элементов.
Звонок на следующие три vector
функции-члены:
size()
max_size()
capacity()
вернет различные значения и предоставит вам некоторое представление о стратегии, используемой при распределении памяти кучи.
1. Если первоначально выделенный объект нуждается в увеличении, может потребоваться перераспределение полностью, а не расширение в соседнюю / смежную секцию памяти. Вовлечение много операций.
2. Для выравнивания памяти может быть добавлено дополнительное заполнение (кратное 4 байтам, чтобы его можно было прочитать с меньшим доступом к памяти)