Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

[C++] Куда уходит память?

535
15 ноября 2011 года
Нездешний
537 / / 17.01.2008
Запускаю тестовое приложение. Одновременно открываю диспетчер задач.
Память на старте приложения: 480 К.
После отработки: 72 540 К

При этом совокупный размер всех строк в результирующем векторе: 6 908 733
Сумма capacity всех строк и самого вектора: 8 468 К

Куда делась остальная память?

Код:
#include <iostream>
#include <vector>
#include <algorithm>

std::vector<std::wstring> GetVariants()
{
    std::vector<std::wstring> v;
    v.push_back(L"a");
    v.push_back(L"b");
    v.push_back(L"c");
    return v;
}

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<std::wstring> v(1);
   
    for (size_t i = 0; i < 12; ++i)
    {
        std::vector<std::wstring> vCopy = v;
        std::vector<std::wstring> vVariants = GetVariants();

        //first
        for (size_t j = 0; j < v.size(); ++j)
        {
            v[j] += vVariants[0];
        }
       
        //remains
        for (size_t j = 1; j < vVariants.size(); ++j)
        {
            copy(vCopy.begin(), vCopy.end(), back_inserter(v));

            for (size_t k = v.size() - vCopy.size(); k < v.size(); ++k)
            {
                v[k] += vVariants[j];
            }
        }
    }

    size_t size = 0;
    size_t capacity = 0;

    for (size_t i = 0; i < v.size(); ++i)
    {
        size += v.size();
        capacity += v.capacity();
    }

    size += v.size();
    capacity += v.capacity();

    cout << "size: " << size << endl << "capacity: " << capacity / 1024 << " K"<< endl;
   
    return 0;
}
240
15 ноября 2011 года
aks
2.5K / / 14.07.2006
Цитата: Нездешний

Память на старте приложения: 480 К.
После отработки: 72 540 К

Как ты это узнал? По диспетчеру задач?

Цитата: Нездешний

При этом совокупный размер всех строк в результирующем векторе: 6 908 733


Как ты это узнал? Если ориентируешься по тому size, что ты выводишь - то это не размер всех строк.

Цитата: Нездешний

Куда делась остальная память?


У тебе тут выделяется уйма временных объектов, на которых тоже тратится память. Учитывая, что ты замерял непонятным способом - вполне возможно что тебе выделили нужное под все эти объекты количество памяти и именно оно и показывается в тебя в таск менеджере, а не реально используемая процессом память. Так бывает. )

535
15 ноября 2011 года
Нездешний
537 / / 17.01.2008
Цитата:
Если ориентируешься по тому size, что ты выводишь - то это не размер всех строк.

Ну да, согласен. Еще sizeof(wchar_t) надо учитывать.
Смотрю по диспетчеру задач. Пусть не совсем точно.
Но это не суть. Цифры же отличаются на порядки. Если увеличить количество итераций цикла хотя бы раза в два - получаю bad alloc memory на каком-то этапе.

240
15 ноября 2011 года
aks
2.5K / / 14.07.2006
Ты посмотри на размер вектора в конце. Возможно ты удивишься его размерам. :) Умнож его на примерный размер (вместе с выделенной под саму строку память) строкового объекта. Наверняка получишь уже более близкие числа. Посмотри каким этот размер будет при увеличении итераций. Наверняка получишь уже более похожие числа. Ато у тебя какой то далеко не показательный метод диагностики на основе capacity.

И еще посчитай сколько итерацией циклов у тебя прокручивается - там очень немаленькие числа. И теперь представь сколько там создается временных объектов, происходят их копирования постоянные, реаллокации памяти. Очень жесткий код в этом плане. )
412
15 ноября 2011 года
grgdvo
323 / / 04.07.2007
Память постепенно отжирает STL. Не знаю как показать под Windows, под Linux вот...
Немного изменил текст

1.cpp:
 
Код:
...
int main(int argc, char* argv[])
... // в конце перед return
int a;
cin >> a;


компилируемся обычно

 
Код:
g++ -o 1 1.cpp


Код:
$ pmap 26227
26227:   ./1
0000000000400000     16K r-x--  /home/user/1
0000000000603000      4K r----  /home/user/1
0000000000604000      4K rw---  /home/user/1
0000000001a58000  73404K rw---    [ anon ]
00007fa3e66d1000   8196K rw---    [ anon ]
00007fa3e74d4000   1396K r-x--  /lib64/libc-2.12.2.so
00007fa3e7631000   2044K -----  /lib64/libc-2.12.2.so
00007fa3e7830000     16K r----  /lib64/libc-2.12.2.so
00007fa3e7834000      4K rw---  /lib64/libc-2.12.2.so
00007fa3e7835000     20K rw---    [ anon ]
00007fa3e783a000     84K r-x--  /lib64/libgcc_s.so.1
00007fa3e784f000   2044K -----  /lib64/libgcc_s.so.1
00007fa3e7a4e000      4K r----  /lib64/libgcc_s.so.1
00007fa3e7a4f000      4K rw---  /lib64/libgcc_s.so.1
00007fa3e7a50000    512K r-x--  /lib64/libm-2.12.2.so
00007fa3e7ad0000   2044K -----  /lib64/libm-2.12.2.so
00007fa3e7ccf000      4K r----  /lib64/libm-2.12.2.so
00007fa3e7cd0000      4K rw---  /lib64/libm-2.12.2.so
00007fa3e7cd1000    944K r-x--  /usr/lib64/gcc/x86_64-pc-linux-gnu/4.5.3/libstdc++.so.6.0.14
00007fa3e7dbd000   2044K -----  /usr/lib64/gcc/x86_64-pc-linux-gnu/4.5.3/libstdc++.so.6.0.14
00007fa3e7fbc000     32K r----  /usr/lib64/gcc/x86_64-pc-linux-gnu/4.5.3/libstdc++.so.6.0.14
00007fa3e7fc4000      8K rw---  /usr/lib64/gcc/x86_64-pc-linux-gnu/4.5.3/libstdc++.so.6.0.14
00007fa3e7fc6000     84K rw---    [ anon ]
00007fa3e7fdb000    120K r-x--  /lib64/ld-2.12.2.so
00007fa3e81c6000     20K rw---    [ anon ]
00007fa3e81f5000     12K rw---    [ anon ]
00007fa3e81f8000      4K r----  /lib64/ld-2.12.2.so
00007fa3e81f9000      4K rw---  /lib64/ld-2.12.2.so
00007fa3e81fa000      4K rw---    [ anon ]
00007fff7e6ab000    132K rw---    [ stack ]
00007fff7e7ff000      4K r-x--    [ anon ]
ffffffffff600000      4K r-x--    [ anon ]
 total            93220K


наблюдаем 75 мегабайт анонимной памяти, то есть которая как бы есть, но ее на самом деле нет... приложение под себя зарезервировало. смотрим далее на strace...

Код:
$ strace ./1
execve("./1", ["./1"], [/* 54 vars */]) = 0
brk(0)                                  = 0x6de000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f936aed8000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
... <skipped>
mprotect(0x7f936a511000, 16384, PROT_READ) = 0
mprotect(0x7f936a72f000, 4096, PROT_READ) = 0
mprotect(0x7f936a9b0000, 4096, PROT_READ) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f936aea7000
mprotect(0x7f936ac9d000, 32768, PROT_READ) = 0
mprotect(0x603000, 4096, PROT_READ)     = 0
mprotect(0x7f936aed9000, 4096, PROT_READ) = 0
munmap(0x7f936aeac000, 179876)          = 0
brk(0)                                  = 0x6de000
brk(0x6ff000)                           = 0x6ff000
brk(0x723000)                           = 0x723000
brk(0x744000)                           = 0x744000
brk(0x765000)                           = 0x765000
brk(0x786000)                           = 0x786000
... <skipped>
brk(0x4d64000)                          = 0x4d64000
brk(0x4d85000)                          = 0x4d85000
brk(0x4da6000)                          = 0x4da6000
brk(0x4dc7000)                          = 0x4dc7000
brk(0x4de8000)                          = 0x4de8000
brk(0x4e09000)                          = 0x4e09000
brk(0x4e2a000)                          = 0x4e2a000
brk(0x4e4b000)                          = 0x4e4b000
brk(0x4e6c000)                          = 0x4e6c000
brk(0x4e8d000)                          = 0x4e8d000
fstat(1, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f936aed7000
write(1, "size: 6908733\n", 14)         = 14
write(1, "capacity: 7251 K\n", 17)      = 17
munmap(0x7f93693b2000, 8392704)         = 0
exit_group(0)                           = ?


обращаем внимание на системный вызов brk - изменение размера сегмента данных программы.
по полному выводу данный вызов был сделан у меня 558 раз (я его не привожу полностью)
доходим до относительно адреса 4e8d000, что примерно 75 мегабайт.
вот он и размер.

не стал я лезть в исходники STL, ох уж это неблагодарное дело
но полагаю, что либо в системе, либо в STL работает низкоуровневый механизм, который пытается предсказать, сколько памяти еще потребуется приложению в близжайшее время и пытается сразу эту памяти резервировать на ближайшее использование (вероятно работает оптимизатор). не могу это подтвердить или опровергнуть - нет возможности дальше глубоко копать.
может кто квалифицровано напишет об этом или даст ссылку.
535
15 ноября 2011 года
Нездешний
537 / / 17.01.2008
[QUOTE=aks]Ты посмотри на размер вектора в конце. Возможно ты удивишься его размерам. Умнож его на примерный размер (вместе с выделенной под саму строку память) строкового объекта. [/QUOTE]Так и считаю - взгляни на переменную size.

С учетом размера wchar_t и в килобайтах
Код:
size_t size = 0;
size_t capacity = 0;

for (size_t i = 0; i < v.size(); ++i)
{
    size += v.size();
    capacity += v.capacity();
}

size += v.size();
capacity += v.capacity();

size = size / 1024 * sizeof(wchar_t);
capacity = capacity / 1024 * sizeof(wchar_t);


size: 13 492 K
capacity: 16 936 K
диспетчер задач (в момент остановки на cout): 72 540 K (в пиках во время работы было до 90)

Про временные объекты - это понятно, не понятно, почему они не освобождаются между итерациями цикла.

PS Кстати, поэкспериментировал с листом - получается примерно то же самое
260
15 ноября 2011 года
Ramon
1.1K / / 16.08.2003
Нафаршировали кучку ж*по вставлятелем и получили кучкин фарш.

PS: Занимаясь нетрадиционным сексом стоит помнить о последствиях.
535
15 ноября 2011 года
Нездешний
537 / / 17.01.2008
[QUOTE=Ramon]Занимаясь нетрадиционным сексом стоит помнить о последствиях.[/QUOTE]Мопед не мой, я только разместил объяву (с) ;)
535
16 ноября 2011 года
Нездешний
537 / / 17.01.2008
Кстати, накладные расходы только на выделение памяти, безо всяких жоповставлятелей
Код:
const size_t MAX_SYMBOLS = 10;
const size_t MAX_STRINGS = 500000;

//-- variant 0
wchar_t *v = new wchar_t [MAX_STRINGS * MAX_SYMBOLS];

//-- variant 1
wchar_t **v = new wchar_t* [MAX_STRINGS];
for (size_t i = 0; i < MAX_STRINGS; ++i)
{
    v = new wchar_t [MAX_SYMBOLS];
}

//-- variant 2
std::wstring ws(MAX_SYMBOLS, L'0');
std::vector<std::wstring> v(MAX_STRINGS, ws);

//-- variant 3
std::vector<wchar_t> ws(MAX_SYMBOLS);
std::vector< std::vector<wchar_t> > v(MAX_STRINGS, ws);


вариант 0: 10 244 К
вариант 1: 41 458 К
вариант 2: 63 104 К
вариант 3: 49 392 К
260
16 ноября 2011 года
Ramon
1.1K / / 16.08.2003
Цитата: Нездешний
Кстати, накладные расходы только на выделение памяти, безо всяких жоповставлятелей
Код:
const size_t MAX_SYMBOLS = 10;
const size_t MAX_STRINGS = 500000;

//-- variant 0
wchar_t *v = new wchar_t [MAX_STRINGS * MAX_SYMBOLS];

//-- variant 1
wchar_t **v = new wchar_t* [MAX_STRINGS];
for (size_t i = 0; i < MAX_STRINGS; ++i)
{
    v = new wchar_t [MAX_SYMBOLS];
}

//-- variant 2
std::wstring ws(MAX_SYMBOLS, L'0');
std::vector<std::wstring> v(MAX_STRINGS, ws);

//-- variant 3
std::vector<wchar_t> ws(MAX_SYMBOLS);
std::vector< std::vector<wchar_t> > v(MAX_STRINGS, ws);


вариант 0: 10 244 К
вариант 1: 41 458 К
вариант 2: 63 104 К
вариант 3: 49 392 К



Здесь все доп. расходы более чем естественны.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог