Пишу алгоритм бинарной сортировки (в целях обучения). Компилятор - MinGW-w64 с флагом оптимизации -o0
Дело в том, что мой код потребляет больше памяти чем я ожидаю..
Структура { ключ, значение, указатель на левого и правого предка } При использовании типов size_t в первом и втором значении в x64 системе логично предположить что итоговый размер структуры - 8+8+8+8 = 32 байта Но на деле при создании 100 000 000 объектов приложение кушает не 3.0гб а 4.5гб, что существенно выше ожидаемого.
Про выравнивание памяти читал и использование #pragma pack(push,1) в глобальной области никак не влияет на ситуацию (что впрочем логично, структура то ровная).
Так же я использовал дополнительную функцию для выделения памяти через malloc, так как мне подсказали что проблема может быть при вызовах new. К сожалению это так же не помогло, но по крайней мере дало возможность следить за размером выделяемой памяти во время исполнения.. Из чего я сделал вывод что размер выделяемой памяти корректен - 3 200 000 000 байт, по крайней мере на этапе выделения.
То есть вероятнее всего это всё таки какая-то оптимизация компилятора. Однако при создании простого массива 32 байтных структур приложение потребляет столько сколько нужно. Следовательно дело в логике выделения памяти (функция Insert(...))
Код который я использую: size_t memCount = 0;
template<typename Type, typename... Args>
Type* Alloc(Args... args)
{
uint8* result = reinterpret_cast<uint8*>(malloc(sizeof(Type)));
memCount += sizeof(Type);
if(result)
return new(reinterpret_cast<Type*>(result)) Type(args...);
return nullptr;
}
template<typename kType, typename Type>
class Node
{
private:
kType key;
Type value;
Node* left;
Node* right;
public:
explicit Node(const kType& key,
const Type& value) : key(key),
value(value),
left(nullptr),
right(nullptr) { }
~Node()
{
if(left) delete left;
if(right) delete right;
}
const bool Insert(const kType& key, const Type& value, const kType& min, const kType& max)
{
if(min == max)
return false;
kType halfMax = (max - min) / 2 + min;
if(key < halfMax)
{
if(!left)
{
left = Alloc<Node>(key, value);
return true;
}
else
return left->Insert(key, value, min, halfMax);
}
else
{
if(!right)
{
right = Alloc<Node>(key, value);
return true;
}
else
return right->Insert(key, value, halfMax, max);
}
return true;
}
};
int main(void)
{
Node<size_t, size_t>* arr = Alloc<Node<size_t, size_t>>(0, 0);
for(size_t x = 1; x < 100000000; x++)
arr->Insert(x, x, numeric_limits<size_t>::min(),
numeric_limits<size_t>::max());
cout << "mem - "<< memCount << endl; // здесь видим 3 200 000 000 (2,9гб), как и должно было быть
system("pause");
return 0;
};
Наблюдаемоге поведение абсолютно логично. Вы не учитываете накладные расходы аллокатора и прочие скрытые "расходы" рантайма. Каждый вызов new
обычно где-то сохраняет аттрибуты выделенной памяти - размер, положение (чтобы потом delete
мог удалить корректно). Вот только в Ваших рассчетах это никак не отражено.
Если допустить, что под это отводится ещё байт 8 (но я не знаю ни компилятор, ни среду, поэтому могу только гадать), то общий размер потребляемой памяти приближается к наблюдаемому.
Что делать?
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Собственно, есть у меня один FXML, к которому я, в зависимости от ситуации, хочу применять один из двух контроллеров, так что вариант с указанием...
Исключение указывает на эту строку StringuserJsonStroke=getJsonFromServer(Stringformat("%s/%d", urlPath), 0);