STL забирает память и не отдает...
От: Krovosos  
Дата: 03.09.09 20:22
Оценка: :)
MS Windows Vista

MS Visual Studio 2008 Express Edition

Проект:


#include <deque>
#include <list>
#include <string>
#include <queue>
#include "stdio.h"
#include "conio.h"
#include "windows.h"
using namespace std;


struct Message
{
    Message(const string& a, const string& b): A(a), B(b){}
    string A,B;
};



int main(int argc, char* argv[])
{
    int STRING_SIZE = 1000;

    int TOTAL = 1000000;

    int N = 1000;

    if (argc > 1) N = atoi(argv[1]);
    if (argc > 2) STRING_SIZE = atoi(argv[2]);

    queue<Message*> z;

    int k = 1;

    printf("Portion size: %d, string size: %d, press ENTER to start\n", N, STRING_SIZE);    getch();


    string A(STRING_SIZE , '0');
    string B(STRING_SIZE  + STRING_SIZE , '1');

    unsigned t = GetTickCount();

    while (TOTAL > 0)
    {
        for (int i = 0; i < N; i++)
            z.push(new Message(A,B));

        while (!z.empty())
        {
            delete z.front();
            z.pop();
        }

        printf("%d ", k);
        k++;
        TOTAL -= N;
    }




    printf("  done in %d ms", GetTickCount() - t); getch();

}


Идея очень проста — необходимо прокачать через очередь (STL queue) один миллион (TOTAL) неких сообщений (Message).
В queue мы храним только указатель (Message*). Новые объекты Message создаются и заносятся в очередь порциями.
Размер порции: N. То бишь заносим N новых сообщений, полностью выбираем их и уничтожаем и опять.

Подчеркиваю — после окончания прокачки сообщений ни одно сообщение не сохраняется — все уничтожены! То есть по идее мы должны выйти на то кол-во памяти, что было при запуске (ну ладно, пускай немного больше).


Итак, проблема: чем больше порция данных, тем больше памяти остается "не у дел" и не возвращается системе после окончания прокачки сообщений. Причем мне лично непонятно — кто и зачем взял эту память и не отдает. Ведь это явно не утечка, а какое-то внутреннее выделение под какие-то нужды.


Чтобы смотреть сколько памяти занято программой я использую Process Explorer от SysInternals. Открываем процесс, выбираем вкладку Performance Graph и смотрим Private Bytes.

Итак, запускаем программу вначале с порцией в тысячу сообщений:

queue.exe 1000

Сразу после запуска видимо, что занято 348 Kb. Жмем Enter и ждем окончания прокачки. Смотрим и видим, что теперь Private Bytes равно 3.7 Mb

Теперь порция в 10000:

queue.exe 10000

После окончания процесс занимает 24.5 Mb памяти!

Ну и дальше, как вы уже догадались, все хужее и хужее:

queue.exe 100000 — 68.7 Mb!!

Ну и наконец:

queue.exe 250000 — 156 Mb!!!

Шедевр! Кто бы мне объяснил — что происходит?

Я могу понять, что STL внутри себя выделяет память. Я не могу понять — почему эта память обратно не вернулась??


stl queue память проблемы
Re: Забыл добавить, что пробовал deque и list...
От: Krovosos  
Дата: 03.09.09 20:27
Оценка:
...вместо queue — эффект тот же.
На кол-во "пропавшей" памяти также прямо влияет размер строк сообщения.
Re: STL забирает память и не отдает...
От: D14  
Дата: 03.09.09 20:48
Оценка:
Здравствуйте, Krovosos, Вы писали:


K>Я могу понять, что STL внутри себя выделяет память. Я не могу понять — почему эта память обратно не вернулась??


Смотреть на показания process explorer'a до того, как отработает деструктор очереди, не очень хорошая идея.
Re[2]: STL забирает память и не отдает...
От: Krovosos  
Дата: 03.09.09 20:54
Оценка:
K>>Я могу понять, что STL внутри себя выделяет память. Я не могу понять — почему эта память обратно не вернулась??

D14>Смотреть на показания process explorer'a до того, как отработает деструктор очереди, не очень хорошая идея.



Я немного переделал пример — то же самое.

Переделал так — сначала прокачивается порциями по N, затем очередь уничтожается и прокачивается порциями по N/10 и затем очередь опять уничтожается. И затем смотрю память. Так вот: память все так же держится, но что интересно — во время второй прокачки память не растет. То есть действительно эта память потом используется...
Re[3]: STL забирает память и не отдает...
От: ononim  
Дата: 03.09.09 21:34
Оценка:
K>>>Я могу понять, что STL внутри себя выделяет память. Я не могу понять — почему эта память обратно не вернулась??
D14>>Смотреть на показания process explorer'a до того, как отработает деструктор очереди, не очень хорошая идея.
K>Я немного переделал пример — то же самое.
K>Переделал так — сначала прокачивается порциями по N, затем очередь уничтожается и прокачивается порциями по N/10 и затем очередь опять уничтожается. И затем смотрю память. Так вот: память все так же держится,

не верю (с)
добавление z = queue<Message*>(); перед getch устраняет сей спецэффект, как и взятие всего кроме getch во вложенную область видимости.
Впрочем оно конечно может быть, не дело это таск манагером расход хипа тюнинговать.
Как много веселых ребят, и все делают велосипед...
Re: STL забирает память и не отдает...
От: zaufi Земля  
Дата: 03.09.09 21:53
Оценка:
Здравствуйте, Krovosos, Вы писали:

K>Я могу понять, что STL внутри себя выделяет память. Я не могу понять — почему эта память обратно не вернулась??

уважаемый дон когданить слышал про аллокаторы в stl?

я выкинул из примера все что связано с виндюками и прогнал под valgrind'ом, который в конце концов выдал мне следующее:
==3963== malloc/free: in use at exit: 0 bytes in 0 blocks.
==3963== malloc/free: 1,015,633 allocs, 1,015,633 frees, 24,004,650 bytes allocated.
==3963== For counts of detected errors, rerun with: -v
==3963== All heap blocks were freed -- no leaks are possible.

zaufi@zaufi /work/tests $ uname -a
Linux zaufi 2.6.30-gentoo-r4 #9 SMP PREEMPT Mon Aug 17 01:32:33 MSD 2009 x86_64 Intel(R) Core(TM)2 Duo CPU T7300 @ 2.00GHz GenuineIntel GNU/Linux
zaufi@zaufi /work/tests $ gcc --version
gcc (Gentoo 4.4.1 p1.0) 4.4.1
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


дык вот возвращаясь к аллокаторам... рекомендую заглянуть в свою реализацию stl и посмотреть как работает дефолтный аллокатор... -- уверен откроете для себя много нового
Re[2]: STL забирает память и не отдает...
От: Krovosos  
Дата: 03.09.09 22:06
Оценка:
K>>Я могу понять, что STL внутри себя выделяет память. Я не могу понять — почему эта память обратно не вернулась??
Z>уважаемый дон когданить слышал про аллокаторы в stl?

Z>я выкинул из примера все что связано с виндюками и прогнал под valgrind'ом, который в конце концов выдал мне следующее:

[...]
Z>==3963== All heap blocks were freed -- no leaks are possible.

То бишь утечек не было...

Z>дык вот возвращаясь к аллокаторам... рекомендую заглянуть в свою реализацию stl и посмотреть как работает дефолтный аллокатор... -- уверен откроете для себя много нового


Ну я примерно представляю как он работает — он берет по мере надобности большие куски памяти у ОС и устраивает на них хипы. Разве нет?

И после выделения и удаления большого числа объектов память не возвращается системе потому что:
a) она сильно дефрагментирована;
b) никто и не собирался возвращать системе выделенные по хипы блоки памяти.

PS В windows есть вызов _heapmin(), который должен вернуть память хипа системе — не помог.
Re[3]: STL забирает память и не отдает...
От: FR  
Дата: 04.09.09 04:58
Оценка:
Здравствуйте, Krovosos, Вы писали:

StlPort + VC ->

#define _STLP_USE_MALLOC и
#define __SYSTEM_HEAP
Re[3]: STL забирает память и не отдает...
От: Anchor  
Дата: 04.09.09 06:20
Оценка: 2 (2)
Здравствуйте, Krovosos, Вы писали:


K>>>Я могу понять, что STL внутри себя выделяет память. Я не могу понять — почему эта память обратно не вернулась??

Z>>уважаемый дон когданить слышал про аллокаторы в stl?

Z>>я выкинул из примера все что связано с виндюками и прогнал под valgrind'ом, который в конце концов выдал мне следующее:

K>[...]
Z>>==3963== All heap blocks were freed -- no leaks are possible.

K>То бишь утечек не было...


Z>>дык вот возвращаясь к аллокаторам... рекомендую заглянуть в свою реализацию stl и посмотреть как работает дефолтный аллокатор... -- уверен откроете для себя много нового


K>Ну я примерно представляю как он работает — он берет по мере надобности большие куски памяти у ОС и устраивает на них хипы. Разве нет?


K>И после выделения и удаления большого числа объектов память не возвращается системе потому что:

K>a) она сильно дефрагментирована;
K>b) никто и не собирался возвращать системе выделенные по хипы блоки памяти.

K>PS В windows есть вызов _heapmin(), который должен вернуть память хипа системе — не помог.



Гриша, выньдовс реально память освобожденную память не покажет, пока не было попыток ей воспользоваться. Страницы маркируются как свободные, но относящиеся к процессу. Запусти рядом процесс жадный до памяти и ты увидишь, как освободится память.
Re: Вообщем, вывод неутешителен.
От: Krovosos  
Дата: 10.09.09 19:01
Оценка:
Единственный разумный выход — свой аллокатор памяти. STLport я попробовал, с разными настройками и результат почти такой же. Лучшими были настройки по умолчанию, но все равно 71 МБайт памяти остался выделен программе.

Приходит в голову только свой аллокатор, который берет большие куски и размещает на них сообщения, а потом уплотняет и пустые куски возвращает системе...
Re[4]: STL забирает память и не отдает...
От: Krovosos  
Дата: 10.09.09 19:02
Оценка:
A>Гриша, выньдовс реально память освобожденную память не покажет, пока не было попыток ей воспользоваться. Страницы маркируются как свободные, но относящиеся к процессу. Запусти рядом процесс жадный до памяти и ты увидишь, как освободится память.

Кто здесь??
Re[2]: Вообщем, вывод неутешителен.
От: quodum  
Дата: 11.09.09 11:33
Оценка:
Здравствуйте, Krovosos, Вы писали:


K>Единственный разумный выход — свой аллокатор памяти. STLport я попробовал, с разными настройками и результат почти такой же. Лучшими были настройки по умолчанию, но все равно 71 МБайт памяти остался выделен программе.


K>Приходит в голову только свой аллокатор, который берет большие куски и размещает на них сообщения, а потом уплотняет и пустые куски возвращает системе...


Эхх... Вы под Win XP гоняете? Попробуйте тогда минимайзнуть окно вашей программы и посмотреть в Task Manager. Удивитесь.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.