С Новым годом! Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.52/25: Рейтинг темы: голосов - 25, средняя оценка - 4.52
0 / 0 / 0
Регистрация: 17.12.2019
Сообщений: 9

new выделяет больше памяти чем положено

17.12.2019, 03:31. Показов 5177. Ответов 22
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте дамы и господа! Как гении программирования, так и начинающие!

Я являюсь программистом с 10 летним стажем, но сегодня моя челюсть выпала в пол! Сегодня я столкнулся с непонятны поведением оператора new. Непонятным в плане потребления оперативной памяти, как на Windows, так и на Linux.

Следующий код работает как и положено, и вопросов не вызывает. Все логично и предсказуемо:
C++
1
2
3
4
5
6
7
8
int main()
{
    int count = 1000000000;
 
    short *v = new short [count];
 
    return 0;
}
Если в процессе отладке поставить точку останова на "return", то можно увидеть, что данная программа как и ожидалось скушала 2Гб оперативной памяти. sizeof(short)*count = 2Гб.

А вот дальше начинаются чудеса:
C++
1
2
3
4
5
6
7
8
9
int main()
{
    int count = 1000000000;
 
    for (int i = 0; i < count; i++)
        new short;
 
    return 0;
}
С глубочайшим удивлением я обнаружил, что планка в 40 Гб пробивается даже не создав и половины элементов.

Это приводит к тому, что односвязный список потребляет кратно больше памяти, чем последовательный контейнер с таким же количеством элементов.

Кто-нибудь может объяснит эту проблему? Почему такой расход памяти? Как с этим бороться?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
17.12.2019, 03:31
Ответы с готовыми решениями:

new выделяет больше памяти, чем задано
Здравия желаю!:) При запуске программы с кодом void main() { char *p; p=new char; cout&lt;&lt;strlen(p); _getch(); ...

New выделяет больше памяти, чем необходимо
Мне нужно переписать из строки String (да, именно String) в динамический массив char, ибо String переменной длины. Выделяю память равную...

Морской бой: расставляется кораблей больше, чем положено
Здравствуйте! Пишу игру &quot;Морской бой&quot; в консоли, и попалась одна неприятная ситуация. Есть функция заполнения поля случайными кораблями,...

22
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
17.12.2019, 04:41
Цитата Сообщение от hydro2020 Посмотреть сообщение
Почему такой расход памяти?
Я конечно не программист и стаж у меня нулевой, поэтому могу ошибаться, но даже я слыхал в общих чертах, что там происходит. Суть в том, что помимо самого блока памяти, менеджер кучи должен хранить информацию об этом блоке(в данном случае она кушает даже больше ресурсов, чем сам блок), также, возможно, что существует минимальный размер выделяемого блока(типо выравнивание).
0
0 / 0 / 0
Регистрация: 17.12.2019
Сообщений: 9
17.12.2019, 12:59  [ТС]
Добавлено через 7 минут
Ну не в 30 же раз!
И выравнивание учитывается функцией sizeof:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
 
class A
{
public:
  char chr = 1;
  A * next = nullptr;
};
 
int main()
{
  std::cout << sizeof(A);
}
Формально объект класса А должен занимать 9 байт на х64 (указатель 8 байт), sizeof вернет с учетом выравнивания 16.
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
17.12.2019, 13:28
hydro2020, в релизе?
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
17.12.2019, 13:44
Цитата Сообщение от hydro2020 Посмотреть сообщение
И выравнивание учитывается функцией sizeof:
При чем здесь new и sizeof?
sizeof - Это информация времени компиляции, а malloc (который обычно внутри new) всегда возвращает наиболее ровный адрес из возможных. Т.е. если вы, например, попросите malloc выделить для вас 1 байт памяти, то выделит она вам минимум 16 байт (на 64-битной платформе).

Вот вам программка для тестов: https://rextester.com/MUCV44429
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <utility>
#include <malloc.h>
 
int main()
{
    void * mptr = malloc(1);
    
    uintptr_t pval = (uintptr_t)mptr;
 
    std::cout << "Is ptr aligned by " 
              << alignof(std::max_align_t)
              << "? - " << (((pval % alignof(std::max_align_t)) == 0) ? "yes" : "no") 
              << std::endl;
    
    // http://man7.org/linux/man-pages/man3/malloc_usable_size.3.html
    std::cout << "How much memory is allocated? - " << malloc_usable_size(mptr) << std::endl;
 
    // The value returned by malloc_usable_size() may be greater than the
    // requested size of the allocation because of alignment and minimum
    // size constraints.
}


Добавлено через 11 минут
Цитата Сообщение от hydro2020 Посмотреть сообщение
Как с этим бороться?
Если вам нужно именно огромное число мелких объектов, то стандартный аллокатор вам не подойдет, нужно его менять на другой.
Таких решений очень много. Загуглите "small object allocator".
2
0 / 0 / 0
Регистрация: 17.12.2019
Сообщений: 9
17.12.2019, 15:30  [ТС]
При чем здесь new и sizeof?
sizeof - Это информация времени компиляции, а malloc (который обычно внутри new) всегда возвращает наиболее ровный адрес из возможных. Т.е. если вы, например, попросите malloc выделить для вас 1 байт памяти, то выделит она вам минимум 16 байт (на 64-битной платформе).
А я не тоже самое написал? Если написать
C++
1
A *a = new A;
, то будет выделено 16 байт.

То что стандартный аллокатор мне не подайдет, я уже понял, проблему давно решил.
Меня интересует природа сего феномена. Её кто то может внятно объяснить. Я думаю никто не будет спорить, что short занимает в памяти 2 байта. 1 миллиард short-ов - 2 Гб. Откуда 64 Гб? Получается что стандартный std::list крайне не эффективен.

Добавлено через 2 минуты
Да, в релизе.
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
17.12.2019, 15:33
Цитата Сообщение от hydro2020 Посмотреть сообщение
Меня интересует природа сего феномена. Её кто то может внятно объяснить.
Дело в том, что malloc заранее не знает какое делать выравнивание (потому что ничего не знает о природе типа, объект которого будет размещаться в выделенной памяти), поэтому делает его максимальным, чтобы подошло под любые нужды.

Добавлено через 1 минуту
Цитата Сообщение от hydro2020 Посмотреть сообщение
А я не тоже самое написал?
Нет, не тоже самое.
Я написал, что malloc пофигу на sizeof для определения выравнивания. Даже для объекта в один байт (sizeof == 1) он все равно выделит 16.
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
17.12.2019, 15:36
Цитата Сообщение от hydro2020 Посмотреть сообщение
, то будет выделено 16 байт.
Он Вам не про Ваш A, а про malloc(1), new char и т.д.

Цитата Сообщение от hydro2020 Посмотреть сообщение
Да, в релизе.
Например, если взять майкросовтовский компилятор, то он на каждый ваш new/malloc может добавлять заголовок размером в 36 байт (или около того, не помню). т.е., на каждый Ваш short придется выделить минимум 38 байт. Но я не могу навскидку сказать, делает ли он так в релизе или только в дебаге.
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
17.12.2019, 15:38
На самом деле, конечно, malloc не обязан ничего не знать про выравнивание в соответствии с размером. Т.е. уж для однобайтных-то объектов может быть сделана такая оптимизация. Какой-нибудь jemalloc наверняка умеет это сразу или позволяет настроить. Но в общем случае он все равно не знает, то ли это массив однобайтных элементов из 5 байт, то ли это один большой объект в 5 байт. У них разные выравнивания, но malloc этой информацией не владеет. Поэтому выравнивает, в общем случае, всегда по максимуму.
0
0 / 0 / 0
Регистрация: 17.12.2019
Сообщений: 9
17.12.2019, 16:02  [ТС]
на каждый Ваш short придется выделить минимум 38 байт
Близко к действительности:
C++
1
2
3
4
5
6
7
8
int main()
{
    std::list<short> l;
    for (int i = 0; i < 1000000000; i++)
         l.insert(l.begin(), 2);
 
    return 0;
}
Жрет 30 Гб в релизе.

Все таки дело в компиляторе или в логике malloc?
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
17.12.2019, 16:05
Цитата Сообщение от hydro2020 Посмотреть сообщение
Все таки дело в компиляторе или в логике malloc?
В логике malloc. У нее нет возможности узнать какое выравнивание ставить в общем случае.

Однако компиляция в дебаге может еще больше увеличить этот размер, потому что потребуется место под отладочную информацию для динамической памяти. Тогда можно сказать, что и в "компиляторе" тоже (точнее в компиляции).

malloc, естественно, у каждого компилятора может быть свой - потому что своя библиотека CRT. Но это неприниципиальный момент. Какая-то версия стандартного аллокатора может чуть меньше завышать, какая-то - чуть больше. Суть не меняется. Завышают они из-за выравнивания.

Еще завышение может быть из-за внутреннего устройства самого аллокатора. Вроде минимального размера блока для выделения памяти.
0
0 / 0 / 0
Регистрация: 17.12.2019
Сообщений: 9
17.12.2019, 16:19  [ТС]
Если sizeof не канает, то можно ли как-то по другому точно узнать сколько памяти выделяет стандартный new для short?
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
17.12.2019, 16:27
hydro2020, в моем примере есть это (для Linux). Вы его не смотрели?
0
0 / 0 / 0
Регистрация: 17.12.2019
Сообщений: 9
17.12.2019, 17:15  [ТС]
Правильно я понимаю, что аналог malloc_usable_size для windows - _msize?

Добавлено через 21 минуту
_msize говорит, что new short - 2 байта. Нестыковочка. Ответ Croessmah ближе к истине.
0
"C with Classes"
2022 / 1404 / 523
Регистрация: 16.08.2014
Сообщений: 5,885
Записей в блоге: 1
17.12.2019, 17:18
hydro2020, посмотри, вроде отзывы хорошие, может что найдешь полезного.
0
0 / 0 / 0
Регистрация: 17.12.2019
Сообщений: 9
17.12.2019, 17:37  [ТС]
Все нашел!
Вот тут:

https://qarchive.ru/488024_s__... peremennyh

16 байт служебной информации + 2 байта шорт = 18 байт. Далее идет выравнивание до кратности 16 байтам. в Итоге new short жрет 32 байта.

Цифры сошлись. Всем спасибо. Вопрос закрыт.
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
17.12.2019, 18:01
Цитата Сообщение от hydro2020 Посмотреть сообщение
для windows - _msize?
Скорее вот такая фиговина:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x64
 
#include <iostream>
#include <windows.h>
#include <avrfsdk.h>
 
typedef ULONG (WINAPI * VerifierEnumResourceFn)(
    HANDLE Process,
    ULONG  Flags,
    ULONG  ResourceType,
    AVRF_RESOURCE_ENUMERATE_CALLBACK ResourceCallback,
    PVOID  EnumerationContext
    );
 
typedef struct HEAP_ENUM_CONTEXT_
{
    ULONG64 AddressToSearch;
} HEAP_ENUM_CONTEXT, *PHEAP_ENUM_CONTEXT;
 
 
ULONG WINAPI FindHeapAllocationCallback(
    PAVRF_HEAP_ALLOCATION HeapAllocation,
    PVOID EnumerationContext,
    PULONG EnumerationLevel
    )
{ 
    PHEAP_ENUM_CONTEXT HeapEnumCtx = (PHEAP_ENUM_CONTEXT)EnumerationContext;
 
    if ((HeapEnumCtx->AddressToSearch >= HeapAllocation->Allocation) &&
        (HeapEnumCtx->AddressToSearch < (HeapAllocation->Allocation + HeapAllocation->AllocationSize)))
    {
 
        printf("user:\t\t%I64p - %I64p\n"
               "system:\t\t%I64p - %I64p\n",
               HeapAllocation->UserAllocation,
               HeapAllocation->UserAllocationSize,
               HeapAllocation->Allocation,
               HeapAllocation->AllocationSize);
    }
    
    
    return ERROR_SUCCESS;
}
 
 
int main()
{
    HMODULE verifier = LoadLibraryExW(L"verifier.dll", 0, 0);
    
    
    VerifierEnumResourceFn pVerifierEnumResource;
    *(FARPROC *)&pVerifierEnumResource = GetProcAddress(verifier, "VerifierEnumerateResource");
    if (!pVerifierEnumResource) 
    {
        printf("%s", "GetProcAddress");
        FreeLibrary(verifier);
        return GetLastError();
    }
    
    HANDLE current_process = GetCurrentProcess();
    
    void * p = new short[1];   
          
   
    HEAP_ENUM_CONTEXT HeapEnumCtx;
    HeapEnumCtx.AddressToSearch = (ULONG64)p;
 
    printf("check address %p\n", p);
    pVerifierEnumResource(
        current_process,
        0,
        AvrfResourceHeapAllocation,
        (AVRF_RESOURCE_ENUMERATE_CALLBACK)FindHeapAllocationCallback,
        &HeapEnumCtx
    );
    
        
    FreeLibrary(verifier);
}
https://rextester.com/YVV59185

Добавлено через 1 минуту
Цитата Сообщение от hydro2020 Посмотреть сообщение
Итоге new short жрет 32 байта.
Сошлось с программой выше.

Добавлено через 4 минуты
Прикольно, если выделить больше 8 байт, то выделяется более килобайта.
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
17.12.2019, 18:47
Цитата Сообщение от hydro2020 Посмотреть сообщение
Ответ Croessmah ближе к истине.
А ничего, что мы об одном и том же говорим?
0
0 / 0 / 0
Регистрация: 17.12.2019
Сообщений: 9
17.12.2019, 18:52  [ТС]
Нет, он говорит о заголовках со служебной информацией, вы об этом не сказали ни слова.
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
17.12.2019, 19:06
Цитата Сообщение от hydro2020 Посмотреть сообщение
Нет, он говорит о заголовках со служебной информацией, вы об этом не сказали ни слова.
Да, потому что это и так очевидно.
К тому же, он называл заголовком весь объем добавляемой информации, хотя из 32 байт - 16 - это выравнивание. Так что таки об одном и том же, просто с разных сторон.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
17.12.2019, 19:06
Помогаю со студенческими работами здесь

Размер выделенной динамической памяти больше чем ожидается
der operator+(char *x) //obj + строка { der newObj; int y=strlen(_name)+strlen(x)+1; cout&lt;&lt;&quot;********* &quot;&lt;&lt;y&lt;&lt;endl; ...

Выделяется больше памяти, чем надо и возвращается из метода набор символов
Задание такое: В этой задаче вам требуется реализовать оператор для уже известного вам класса String. Однако на этот раз оператор должен...

Трёхмерный вектор занимает в четыре раза больше памяти, чем должен
Создаю трёхмерный вектор таким способом vector&lt;vector&lt;vector&lt;int&gt; &gt; &gt; dp; int n, k; void initializeVector () { dp.resize(n +...

Разработать программу, которая динамически выделяет 100 блоков памяти по 1000 байт каждый и освобождает их
Всем привет. Подкинули на учебе вот такое задание - Напишите программу, которая динамически выделяет 100 блоков памяти по 1000 байт каж-дый...

Засунуть в ноут больше чем положено!
Возможно ли установить в ноутбук больше оперативной памяти чем заявлено производителем? Допустим произв пишет макс 8 гигов, а я хочу 12...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её. Последовательность действий:. . .
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru