Re[11]: собеседования, Реверс списка
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 14.10.13 17:52
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Да вы, батенька, считать не умеете. ))


Я честно говоря не в курсе, что там в vector происходит. Запрашивается всего 660мб, а внезапно это превращается в 1920
Re[9]: собеседования, Реверс списка
От: Erop Россия  
Дата: 14.10.13 18:47
Оценка:
Здравствуйте, Marty, Вы писали:

E>>ну, например, как ты думаешь, если вот тупо взять и написать на плюсах std::vector<char> и начать в него добавлять по одному, миллион символов добавить удостся?..


M>А ты этим что хотел доказать?


Я задал вопрос, я, например, думал и думаю, что метров до 100 можно не парится, потом могут начаться варианты...


M>Результат

M>
M>...
M>i = 689594368
M>i = 689595392
M>Error: bad allocation
M>



Дык о том и речь...
Жаль, что мы так и не услышали начальника транспортного цеха...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[19]: собеседования, Реверс списка
От: Evgeny.Panasyuk Россия  
Дата: 14.10.13 19:12
Оценка:
Здравствуйте, Ikemefula, Вы писали:

EP>>Если ты утверждаешь что это фрагментация, то попробуй сделать (или попроси Marty) тот же тест но добавив и v.reserve(1000*1000*680); в начало.

I>Конечно фрагментация, т.к. требуемый размер всей свободной памяти больше чем запрашиваемый.

У него не хватает памяти после примерно выделенного размера, когда уже произошло ~50 реаллокаций.
Так вот, раз ты говоришь что дальше ошибка из-за фрагментации — я предлагаю тебе заменить эти ~50 реаллокаций одним reserve'ом, и начать с этой точки, без фрагментации.
То есть у нас будет одна аллокация на 680MB, и мы будем делать push_back, который вызовет попытку реаллокации в не фрагментированной куче.
Re[16]: собеседования, Реверс списка
От: Evgeny.Panasyuk Россия  
Дата: 14.10.13 19:21
Оценка:
Здравствуйте, Ikemefula, Вы писали:

EP>>Тут вообще-то другой случай, практически не относящийся к фрагментации

EP>>Вот тебе задачка: какого максимального размера удастся получить vector<char>, делая while(true) x.push_back('\0');, без всяких reserve, при grow factor 1.5 и при идеальной стратегии выделения памяти на x32 (учитывая 2GiB доступной памяти)?

I>Это вроде как первый пример Marty , там нет никакого reserve и тд. Но вобще при grow factor 1.5 и идеальной стратегии должна выюзаться почти вся память.


grow factor=1.5, то есть после реаллокации capacity увеличивается в 1.5 раза.
Во время реаллокации в памяти находится и исходный storage, и новый, так как данные нужно перекинуть из одного места, в другое. Если данные посложнее char, то вызываются конструкторы копирования/перемещения, деструктятся старые объекты.
Это означает, что для реаллокации нам нужно всего 2.5x памяти от текущей capacity.
Для 2GB всего свободной памяти оценка сверху получается 2GB/2.5 = сколько посчитаешь сам, и сравнишь с тем что получилось у Marty.
Re[14]: собеседования, Реверс списка
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 14.10.13 19:23
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Это был сарказм. Поэтому я и не понял к чему был твой тест в ответ на сообщение Erop'а.

Ну, если б это было серьезно сказано, то я Erop'а опроверг. А если сарказм, то я его мысль просто проиллюстрировал

EP>Что не удивительно, учитывая что у MSVC'шного вектора capacity растёт на 50%. То есть в момент реаллокации в памяти находится 2.5x от текущей capacity.


В этом случае падеж закономерен — адресного пространства 2Гб не хватает. Тут realloc мог бы помочь, Ikemefula про него был прав.

EP>Мне интересен был твой результат.

А чем интересен именно мой результат, а не любой другой результат, полученный тем же кодом?

Мой результат такой (код в конце):

Тупое выделение куска памяти и освобождение (тест возможности аллокации куска памяти максимального размера):
...
Try to reserve 1900000000 or more chars
Memory reserved
Char at random position: 'W'
Test passed
Try to reserve 2000000000 or more chars
Error: bad allocation


Тесты на фрагментацию

Заполнение вектора char по одному элементу (если увеличить лимиты, у меня выскакивает bad_alloc):
...
i = 649998336
i = 649999360
Char at random position: 'R'
V1 capacity: 689596368
V1 next allocation size prediction: 1034394552
V1 next allocation size prediction and currently allocated space: 1723990920


Заполнение вектора char по одному элементу, затем резервирование двойного размера (если увеличить лимиты, у меня выскакивает bad_alloc):
...
i = 439998464
i = 439999488
Char at random position: 'R'
V1 capacity: 459730912
Vector 2
Memory reserved
First copy added
Second copy added
Char at random position in vector 2: ')'
V2 capacity: 880010000
V1+V2 capacity: 1339740912


Вообщем, Ikemefula во многом прав, по крайней мере стандартный менеджер памяти от MSVS2005 не слишком хорош; также алгоритм резервирования памяти у вектора мог бы быть по-скромнее — начиная с какого-то лимита (например, 300мб на 32 битах) можно резервировать не 1.5, а 1.1, к примеру, а если достигаем 500мб — то можно хапать почти все оставшееся (ясно, что программа явно содержит один гигантский кусок данных, а остальное — мелочь в любом случае), не 1.1 — 1.5, а 2-3, а остатки на мелочь оставить.

Код (хидеры опустил)
void make_vector( int size )
{
    std::vector<char> v;
    std::cout<<"Try to reserve "<<size<<" or more chars\n";
    v.reserve(size);
    std::cout<<"Memory reserved\n";
    for(int i=0; i!=size; ++i)
       {
        //if (i && i%1024 == 0) std::cout<<"i = "<<i<<"\n";
        char ch = ' ' + (char)(i%64);
        v.push_back(ch);
       }
    std::cout<<"Char at random position: '"<<v[GetTickCount()%size]<<"'\n";
    std::cout<<"Test passed\n";
}


int main(int argc, char* argv[])
   {
    try{
        if (argc>2) 
           {
            make_vector(  450000000 );
            make_vector(  500000000 );
            make_vector(  600000000 );
            make_vector(  700000000 );
            make_vector(  800000000 );
            make_vector(  900000000 );
            make_vector( 1000000000 );
            make_vector( 1100000000 );
            make_vector( 1200000000 );
            make_vector( 1300000000 );
            make_vector( 1400000000 );
            make_vector( 1500000000 );
            make_vector( 1600000000 );
            make_vector( 1700000000 );
            make_vector( 1800000000 );
            make_vector( 1900000000 );
            make_vector( 2000000000 );
            make_vector( 2100000000 );
            make_vector( 2200000000 );
            make_vector( 2300000000 );
            make_vector( 2400000000 );
            make_vector( 2500000000 );
            make_vector( 2600000000 );
            make_vector( 2700000000 );
            make_vector( 2800000000 );
            make_vector( 2900000000 );
            make_vector( 3000000000 );
            return 0;
           }

        //const int maxI = 1024*1024*1024;
        const int maxI = argc>1 ? 440000000 : 650000000 ; 
        std::vector<char> v;
        //std::deque<char> v;
        for(int i=0; i!=maxI; ++i)
           {
            if (i && i%1024 == 0) std::cout<<"i = "<<i<<"\n";
            char ch = ' ' + (char)(i%64);
            v.push_back(ch);
           }
        std::cout<<"Char at random position: '"<<v[GetTickCount()%maxI]<<"'\n";
        std::cout<<"V1 capacity: "<<v.capacity()<<"\n";

        if (argc<2) 
           {
            std::cout<<"V1 next allocation size prediction: "<<(3*v.capacity()/2)<<"\n";
            std::cout<<"V1 next allocation size prediction and currently allocated space: "<<(3*v.capacity()/2 + v.capacity())<<"\n";
            return 0;
           }

        std::cout<<"Vector 2\n";
        std::vector<char> v2;
        v2.reserve(2*v.size()+10000);
        std::cout<<"Memory reserved\n";
        v2.insert(v2.end(), v.begin(), v.end());
        std::cout<<"First copy added\n";
        v2.insert(v2.end(), v.begin(), v.end());
        std::cout<<"Second copy added\n";
        std::cout<<"Char at random position in vector 2: '"<<v2[GetTickCount()%(2*maxI)]<<"'\n";
        std::cout<<"V2 capacity: "<<v2.capacity()<<"\n";
        std::cout<<"V1+V2 capacity: "<<(v.capacity()+v2.capacity())<<"\n";
       }
    catch( const std::exception &e )
       {
        std::cout<<"Error: "<<e.what()<<"\n";
       }
    catch( ... )
       {
        std::cout<<"Error: unknown\n";
       }
    
    return 0;
   }
Маньяк Робокряк колесит по городу
Re[16]: собеседования, Реверс списка
От: Evgeny.Panasyuk Россия  
Дата: 14.10.13 19:27
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>Своим примером ты показал, что VirtualAlloc ничем не помогает, а помогает grow factor 1.5 и то, слабовато, т.е. все равно всё сдохло. То есть, все работает, как и должно.

V>>Ты утверждал, что все заткнется из-за дефрагментации, не?
V>>И облажался, по результатам теста. Если в тесте после грубо 660 метров не удалось выделить память, то это значит, что всего было запрошено порядка 660*3=1980 метров. ЧТД.
I>А почему на три надо помножать, если добавляем по одному байту ?

Если добавляем по одному байту к capacity, то получаем квадратичную сложность Я даже видел такие реализации (но то был не vector)
Умножать на три нужно при grow factor = 2
Re[15]: собеседования, Реверс списка
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 14.10.13 19:37
Оценка:
Здравствуйте, Marty, Вы писали:

Вышенаписанное вообщем-то подтверждает точку зрения Ikemefula, что некоторые менеджеры памяти для C++ не совсем совершенны. Но чтобы он не слишком радовался своей правоте, предлагаю ему привести аналогичные тесты его любимого языка с его любимым GC, чтобы было о чем дальше дискутировать.

PS Ну и да, менеджер от MSVS2005 (по крайней мере), не совершенен. Было бы круто, если бы была возможность у приложения при старте задавать ему хинты — типа мы будем использовать очень большой кусок памяти единовременно, а остатки используй на мелочевку. Ну или вообще — приложение же свое, для основной мега задачи резервируй сколько по максимуму, а крошки пусть ММ оставит на текущие расходы.
Маньяк Робокряк колесит по городу
Re[14]: собеседования, Реверс списка
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 14.10.13 19:39
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Егор прочитал непойми где что "VirtualAlloc помогает". Объяснить, как именно помогает VirtualAlloc, он не смог, ограничился "Почитай Рихтера" и "читай как устроены хипы"


Я признаться, тоже не понял, как VirtualAlloc поможет. Тут скорее нужен свой аллокатор с использованием memory mapped files.

I>Своим примером ты показал, что VirtualAlloc ничем не помогает, а помогает grow factor 1.5 и то, слабовато, т.е. все равно всё сдохло. То есть, все работает, как и должно.

А ты покажи, как GC на раз решает проблемы
Маньяк Робокряк колесит по городу
Re[10]: собеседования, Реверс списка
От: Erop Россия  
Дата: 14.10.13 19:50
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Эх, чОрт, не помог VirtualAlloc


А чему он, по твоему, не помог?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[15]: собеседования, Реверс списка
От: Evgeny.Panasyuk Россия  
Дата: 14.10.13 19:51
Оценка:
Здравствуйте, Marty, Вы писали:

EP>>Что не удивительно, учитывая что у MSVC'шного вектора capacity растёт на 50%. То есть в момент реаллокации в памяти находится 2.5x от текущей capacity.

M>В этом случае падеж закономерен — адресного пространства 2Гб не хватает. Тут realloc мог бы помочь, Ikemefula про него был прав.

Падение закономерно, потому что у тебя съедается практически вся доступная память, а не из-за фрагментации.

EP>>Мне интересен был твой результат.

M>А чем интересен именно мой результат, а не любой другой результат, полученный тем же кодом?

1. достаточно независимый
2. раз уже был один результат, не хотел вводить путаницу
3. показать лёгкость замены вектора на деку (которой afaik нет в стандартном .net'е)

M>Мой результат такой (код в конце):



M>Тесты на фрагментацию

M>Заполнение вектора char по одному элементу (если увеличить лимиты, у меня выскакивает bad_alloc):
M>
M>...
M>i = 649998336
M>i = 649999360
M>Char at random position: 'R'
M>V1 capacity: 689596368
M>V1 next allocation size prediction: 1034394552
M>V1 next allocation size prediction and currently allocated space: 1723990920
M>


Сделай тоже самое, но добавив в начало v.reserve(1000*1000*700) — и ты увидишь, что это не фрагментация.

M>Вообщем, Ikemefula во многом прав


В чём-то он прав. И в тех случаях где он действительно прав — я с ним согласен (пруф
Автор: Ikemefula
Дата: 11.10.13
).
Но в этом конкретном случае — он не прав, тут проблема не во фрагментации

M>по крайней мере стандартный менеджер памяти от MSVS2005 не слишком хорош; также алгоритм резервирования памяти у вектора мог бы быть по-скромнее — начиная с какого-то лимита (например, 300мб на 32 битах) можно резервировать не 1.5, а 1.1, к примеру, а если достигаем 500мб — то можно хапать почти все оставшееся (ясно, что программа явно содержит один гигантский кусок данных, а остальное — мелочь в любом случае), не 1.1 — 1.5, а 2-3, а остатки на мелочь оставить.


Допустим для x64 — ты какой бы порог взял? Для некоторых приложений 1.1 после 500MB было бы слишком тормозно.
А там где реально нужна экономия, всегда можно делать reserve вручную, с какой угодно стратегией.
Re[17]: собеседования, Реверс списка
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 14.10.13 19:54
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

I>>Это вроде как первый пример Marty , там нет никакого reserve и тд. Но вобще при grow factor 1.5 и идеальной стратегии должна выюзаться почти вся память.

Неправильный ответ.

EP>Это означает, что для реаллокации нам нужно всего 2.5x памяти от текущей capacity.

EP>Для 2GB всего свободной памяти оценка сверху получается 2GB/2.5 = сколько посчитаешь сам, и сравнишь с тем что получилось у Marty.

Правильный ответ.
Если быть точным, у меня 650Мб получилось против теоретических 800, но это погрешности. Но тут еще зависит от изначального размера, от которого потом grow идет — т.е если сейчас 650мб текущего размера требует для переаллокации 975мб непрерывного куска и 1625мб памяти всего, то если бы было на последнем шаге 600 — 600*1.5+600 = 1500 — данных влезло бы на 900мб.

А вообще, было бы круто, если бы аллокаторы поддерживали изменение grow factor, и его можно было бы поменять через интерфейс контейнера. Что ни говори, а 32 бита еще не скоро сойдут с дистанции, а объемы данных растут постоянно. Закиньте что ли предложение в комитет
Маньяк Робокряк колесит по городу
Re[16]: собеседования, Реверс списка
От: Evgeny.Panasyuk Россия  
Дата: 14.10.13 20:00
Оценка: +2
Здравствуйте, Marty, Вы писали:

M> Вышенаписанное вообщем-то подтверждает точку зрения Ikemefula, что некоторые менеджеры памяти для C++ не совсем совершенны.


В твоём примере как раз видно, что если и есть фрагментация, то мизерная. Теоретический потолок — 2GiB/2.5, причём это без dll'ек, без стэка и т.п.
Посмотри, например, по каким адресам у тебя dll'ки загрузились, куда .exe, где стэк находится и т.п
Re[15]: собеседования, Реверс списка
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 14.10.13 20:01
Оценка:
Здравствуйте, vdimas, Вы писали:

I>>Своим примером ты показал, что VirtualAlloc ничем не помогает, а помогает grow factor 1.5 и то, слабовато, т.е. все равно всё сдохло. То есть, все работает, как и должно.


V>Ты утверждал, что все заткнется из-за дефрагментации, не?

V>И облажался, по результатам теста. Если в тесте после грубо 660 метров не удалось выделить память, то это значит, что всего было запрошено порядка 660*3=1980 метров. ЧТД.

Ты тут не прав
660 метров занято. Если grow 1.5 — требуется еще один непрерывный кусок ~1Гб; вместе с уже аллоцированным — 1.6-1.7Гб, но это два куска, это максимум расхода памяти в процессе переалокации; после реаллока будет занято 1Гб. Ну и если при занятом куске в 660Мб нет места для цельного куска 1Гб — память таки да, фрагментирована, при том, что под данные у Win32 процесса обычно есть честные 2Гб.
Маньяк Робокряк колесит по городу
Re[15]: собеседования, Реверс списка
От: Erop Россия  
Дата: 14.10.13 20:01
Оценка: 3 (1)
Здравствуйте, Marty, Вы писали:

M>Я признаться, тоже не понял, как VirtualAlloc поможет. Тут скорее нужен свой аллокатор с использованием memory mapped files.


Я же уже писал.
Есть два эффекта.
1) Когда куче не хватает памяти, она кусает по VA ещё сегмент, в котором проолжает нарезать блоки, потом ещё сегмент, ещё сегмент и т. д. Трудность в том, что эти сегменты трудно освобождать, так как надо понять, что там нет занятых блоков...

2) В программе может быть несколько компонент, пользующихся разными аллокаторами. И тогда все проблемы с сегментами из (1) или ещё какими возводятся в квадрат, и тогда вот и наступает клизма с фрагментацией АП.

Но, если все аллокаторы в программе аллокируют слишком большие куски сразу по VA, то тогда их можно освобождать, вопервых, и они могут переиспользоваться потом из ДРУГИХ аллокаторов, во-вторых...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[17]: собеседования, Реверс списка
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 14.10.13 20:11
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

M>> Вышенаписанное вообщем-то подтверждает точку зрения Ikemefula, что некоторые менеджеры памяти для C++ не совсем совершенны.


EP>В твоём примере как раз видно, что если и есть фрагментация, то мизерная. Теоретический потолок — 2GiB/2.5, причём это без dll'ек, без стэка и т.п.

EP>Посмотри, например, по каким адресам у тебя dll'ки загрузились, куда .exe, где стэк находится и т.п

Мизер не мизер, но память делит как минимум на две половины, из которых целое не склеить. Стек — да, он скорее всего однозначно в АП пользовательских данных процесса. По поводу dll-ек — утверждать ничего не буду, но они разве не в другие 2Гб АП грузятся? Или те 2Гб только на нужды ядра и user-space dll там не селятся? Тогда да, надо бы пройтись еще по dll-кам процесса, где они лежат и чье место на самом деле занимают.
Но мне это делать лень Я свою задачу выполнил — подкинул на вентилятордал повод для дальнейших исследований и поисков истины уж простите, но дискуссия интересная, да и давно я в проф. форуме не обозначался
Маньяк Робокряк колесит по городу
Re[15]: собеседования, Реверс списка
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 14.10.13 20:19
Оценка:
Здравствуйте, Marty, Вы писали:

I>>Своим примером ты показал, что VirtualAlloc ничем не помогает, а помогает grow factor 1.5 и то, слабовато, т.е. все равно всё сдохло. То есть, все работает, как и должно.

M>А ты покажи, как GC на раз решает проблемы

Это не интересно, как GC перемещает объекты. Интереснее, как можно выделить 20мб и при этом GC не сможет выделить ни байта, хотя свободной памяти будет ажно 20гб
Re[16]: собеседования, Реверс списка
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 14.10.13 20:41
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Marty, Вы писали:


EP>>>Что не удивительно, учитывая что у MSVC'шного вектора capacity растёт на 50%. То есть в момент реаллокации в памяти находится 2.5x от текущей capacity.

M>>В этом случае падеж закономерен — адресного пространства 2Гб не хватает. Тут realloc мог бы помочь, Ikemefula про него был прав.

EP>Падение закономерно, потому что у тебя съедается практически вся доступная память, а не из-за фрагментации.

Да, но realloc, который при 1.5 grow factor требует только того, чтобы сразу за 1 используемой памяти было доступно еще 0.5, не упал бы. Тут нужен оператор renew Напишите кто-нибудь в комитет


EP>>>Мне интересен был твой результат.

M>>А чем интересен именно мой результат, а не любой другой результат, полученный тем же кодом?

EP>1. достаточно независимый

EP>2. раз уже был один результат, не хотел вводить путаницу
Ок

EP>3. показать лёгкость замены вектора на деку (которой afaik нет в стандартном .net'е)

Дека не гарантирует непрерывности куска памяти, а вектор гарантирует. В данном случае деке пофигу, но если непрерывность критична (насчет .Net не знаю) — то ой.

M>>Мой результат такой (код в конце):



M>>Тесты на фрагментацию

M>>Заполнение вектора char по одному элементу (если увеличить лимиты, у меня выскакивает bad_alloc):
EP>Сделай тоже самое, но добавив в начало v.reserve(1000*1000*700) — и ты увидишь, что это не фрагментация.
А что это? первый тест не смог 2Гб выделить, но 1.9Гб одним куском — смог. Впрочем — да, наверно просто не хватает места на переаллокацию. Но reserve в начале просто вычеркнет этот тест из тестов на фрагментацию, и впишет его в тесты на макс объем доступной памяти из п.1.

M>>Вообщем, Ikemefula во многом прав


EP>В чём-то он прав. И в тех случаях где он действительно прав — я с ним согласен (пруф
Автор: Ikemefula
Дата: 11.10.13
).

Лень смотреть потом гляну.

EP>Но в этом конкретном случае — он не прав, тут проблема не во фрагментации

Да, скорее не во фрагментации, чем во фрагментации.

M>>по крайней мере стандартный менеджер памяти от MSVS2005 не слишком хорош; также алгоритм резервирования памяти у вектора мог бы быть по-скромнее — начиная с какого-то лимита (например, 300мб на 32 битах) можно резервировать не 1.5, а 1.1, к примеру, а если достигаем 500мб — то можно хапать почти все оставшееся (ясно, что программа явно содержит один гигантский кусок данных, а остальное — мелочь в любом случае), не 1.1 — 1.5, а 2-3, а остатки на мелочь оставить.


EP>Допустим для x64 — ты какой бы порог взял? Для некоторых приложений 1.1 после 500MB было бы слишком тормозно.

Ну, для 64 бит пока вроде не проблемы фрагментации АП как класса задач А для 32 — да, тормозно, но ковыляло бы

EP>А там где реально нужна экономия, всегда можно делать reserve вручную, с какой угодно стратегией.

Сейчас запустил тест с reserve и проверкой capcity — пока не закончился, но предполагаю, что capcity будет больше reserve. Результат отпишу чуть позже
Маньяк Робокряк колесит по городу
Re[18]: собеседования, Реверс списка
От: Evgeny.Panasyuk Россия  
Дата: 14.10.13 20:42
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>>> Вышенаписанное вообщем-то подтверждает точку зрения Ikemefula, что некоторые менеджеры памяти для C++ не совсем совершенны.

EP>>В твоём примере как раз видно, что если и есть фрагментация, то мизерная. Теоретический потолок — 2GiB/2.5, причём это без dll'ек, без стэка и т.п.
EP>>Посмотри, например, по каким адресам у тебя dll'ки загрузились, куда .exe, где стэк находится и т.п
M>Мизер не мизер, но память делит как минимум на две половины, из которых целое не склеить.

Это не фрагментация.
Фрагметация — это пример который приводил Ikemefula раньше — там где посредине АП есть что-то небольшое, что мешает выделить большой кусок.
Тут же просто нехватка памяти. Если бы те ~50 аллокаций что были у тебя действительно фрагментировали бы кучу — то аллокация сфейлилась бы гораздо раньше.

M>Стек — да, он скорее всего однозначно в АП пользовательских данных процесса. По поводу dll-ек — утверждать ничего не буду, но они разве не в другие 2Гб АП грузятся? Или те 2Гб только на нужды ядра и user-space dll там не селятся? Тогда да, надо бы пройтись еще по dll-кам процесса, где они лежат и чье место на самом деле занимают.

M>Но мне это делать лень Я свою задачу выполнил — подкинул на вентилятордал повод для дальнейших исследований и поисков истины уж простите, но дискуссия интересная, да и давно я в проф. форуме не обозначался

На MSVC2010SP1x32 (не знаю что там у тебя) самый низкий адрес у msvcp100.dll — 0x664C0000. Верх .exe'шника — 0x00A27000. ESP = 0x0140FBC0.
Разница между msvcp100.dll и ESP ~ 1695MB (мегабайт, не мебибайт). Делим на 2.5: 678 MB — что-то знакомое
Re[17]: собеседования, Реверс списка
От: Evgeny.Panasyuk Россия  
Дата: 14.10.13 20:56
Оценка:
Здравствуйте, Marty, Вы писали:

EP>>>>Что не удивительно, учитывая что у MSVC'шного вектора capacity растёт на 50%. То есть в момент реаллокации в памяти находится 2.5x от текущей capacity.

M>>>В этом случае падеж закономерен — адресного пространства 2Гб не хватает. Тут realloc мог бы помочь, Ikemefula про него был прав.
EP>>Падение закономерно, потому что у тебя съедается практически вся доступная память, а не из-за фрагментации.
M>Да, но realloc, который при 1.5 grow factor требует только того, чтобы сразу за 1 используемой памяти было доступно еще 0.5, не упал бы. Тут нужен оператор renew Напишите кто-нибудь в комитет

Почему бы и нет

EP>>3. показать лёгкость замены вектора на деку (которой afaik нет в стандартном .net'е)

M>Дека не гарантирует непрерывности куска памяти, а вектор гарантирует. В данном случае деке пофигу, но если непрерывность критична (насчет .Net не знаю) — то ой.

Непрерывность вектора действительно иногда бывает полезна сама по себе. Но чаще она полезна просто как самый быстрый кусок данных.
Ikemefula вроде говорил что у него где-то на .net с vector-like были проблемы, да причём такие, что он теперь векторов как огня боится. Вот я и удивляюсь — почему в .net нет стандартной деки (или всё-таки есть?).

M>>>Мой результат такой (код в конце):


M>>>Тесты на фрагментацию

M>>>Заполнение вектора char по одному элементу (если увеличить лимиты, у меня выскакивает bad_alloc):
EP>>Сделай тоже самое, но добавив в начало v.reserve(1000*1000*700) — и ты увидишь, что это не фрагментация.
M>А что это? первый тест не смог 2Гб выделить, но 1.9Гб одним куском — смог. Впрочем — да, наверно просто не хватает места на переаллокацию.

Это возможность убрать ~49 первых реаллокаций и убедится что дело не в них. (с обсуждения этих реаллокаций как раз и начинался этот топик)

M>>>по крайней мере стандартный менеджер памяти от MSVS2005 не слишком хорош; также алгоритм резервирования памяти у вектора мог бы быть по-скромнее — начиная с какого-то лимита (например, 300мб на 32 битах) можно резервировать не 1.5, а 1.1, к примеру, а если достигаем 500мб — то можно хапать почти все оставшееся (ясно, что программа явно содержит один гигантский кусок данных, а остальное — мелочь в любом случае), не 1.1 — 1.5, а 2-3, а остатки на мелочь оставить.

EP>>Допустим для x64 — ты какой бы порог взял? Для некоторых приложений 1.1 после 500MB было бы слишком тормозно.
M>Ну, для 64 бит пока вроде не проблемы фрагментации АП как класса задач А для 32 — да, тормозно, но ковыляло бы

Я думал мы тут уже не об фрагментации говорим, а об свободной памяти — она ведь не бесконечна. И точно такая же проблема возможна и на x64, кстати, как раз потому, что дело не во фрагментации.
Re[19]: собеседования, Реверс списка
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 14.10.13 20:57
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

M>>>> Вышенаписанное вообщем-то подтверждает точку зрения Ikemefula, что некоторые менеджеры памяти для C++ не совсем совершенны.

EP>>>В твоём примере как раз видно, что если и есть фрагментация, то мизерная. Теоретический потолок — 2GiB/2.5, причём это без dll'ек, без стэка и т.п.
EP>>>Посмотри, например, по каким адресам у тебя dll'ки загрузились, куда .exe, где стэк находится и т.п
M>>Мизер не мизер, но память делит как минимум на две половины, из которых целое не склеить.

EP>Это не фрагментация.

EP>Фрагметация — это пример который приводил Ikemefula раньше — там где посредине АП есть что-то небольшое, что мешает выделить большой кусок.
Я вроде под фрагментацией тоже самое и подразумеваю. Или не?

EP>Тут же просто нехватка памяти. Если бы те ~50 аллокаций что были у тебя действительно фрагментировали бы кучу — то аллокация сфейлилась бы гораздо раньше.

Вопрос насколько они кучу сфрагментировали, может совсем чуть-чуть, только в серединке

M>>Стек — да, он скорее всего однозначно в АП пользовательских данных процесса. По поводу dll-ек — утверждать ничего не буду, но они разве не в другие 2Гб АП грузятся? Или те 2Гб только на нужды ядра и user-space dll


EP>На MSVC2010SP1x32 (не знаю что там у тебя) самый низкий адрес у msvcp100.dll — 0x664C0000. Верх .exe'шника — 0x00A27000. ESP = 0x0140FBC0.

EP>Разница между msvcp100.dll и ESP ~ 1695MB (мегабайт, не мебибайт). Делим на 2.5: 678 MB — что-то знакомое
Я писал, у меня MSVC2005, но думаю, особых изменений с тех пор не было.

Ок, похоже на правду Как бы прошу заметить, что я тут независимое расследование провожу, так что попрошу без подxyzколок
Маньяк Робокряк колесит по городу
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.