Данный список не в коей мере не претендует на полноту или ещё на что-либо. Просто набор моментов, которые показались мне интересными.
Неожиданное исчерпание свободной памяти.
Возникает при использовании пиннинга памяти. Не обязательно явном. Например при использовании асинхронного ввода-вывода ран-тайм скорее всего сам будет делать пиннинг памяти. В CLI такая возможность так же присутствует в явном виде, в Java — не знаю. Суть пиннинга — запрещение перемещения объекта в памяти. Это может препятствовать "уплотнению" используемой памяти во время сборки мусора, таким образом используемая память будет сильно фрагментирована и "кпд" использования памяти резко снижается. Здесь можно прочитать более подробно. Кратко суть такая: в C# при использовании асинхронных сокетов (IOCP) в сервере заканчивалось 3GB памяти (летели OutOfMemoryException), хотя "полезных" данных в памяти было примерно 200MB.
Постепенная и периодическая деградация производительности и рост используемой памяти под нагрузкой.
Подробности здесь. Кратко: в Java при использовании WeakHashMap и включении Concurrent GC вместо штатного начали проявляться упомянутые эффекты. Оказалось, что под нагрузкой большую часть элементов WeakHashMap постоянно "трогают", хотя реально не используют. Это "троганье" предотвращало удаление каких-либо объектов из WeakHashMap вообще. Соответственно он неограниченно рос, пока весь сервер не затыкался на некоторое время. Во время затыкания элементы WeakHashMap никто не "трогал", и соотв. они все удалялись. Все становится хорошо. А потом по новой. Со штатным GC такой эффект не наблюдается.
Ну более-менее стандартная проблема с временем жизни и владением объектами.
Многие по началу считают, что при наличии GC этих проблем просто нет. К сожалению это не так. GC обеспечивает только базовую потокобезопасность для ссылок (можно захватывать новые ссылки на объект, только если у тебя уже есть хотя бы одна), но не обеспечивает строгой потокобезопасности для ссылок (возможность захватывать новые ссылки на объект, если у тебя ещё нет ни одной). Т.о. если необходима строгая потокобезопасность, то — мьютекс + счётчик ссылок... Что-то мне это напоминает...
Один из примеров можно поглядеть здесь
Первые две проблемы от того, что GC хотят сделать полностью прозрачным и скрытым от программиста, типа он просто магически работает. К сожалению, полностью прозрачен он только на абстрактном уровне. Когда дело доходит до самых деталей начинается самое интересное — побочные эффекты GC становятся видны. Отсюда ещё одно неприятное следствие — программа хорошо работающая с одним типом или даже скорее реализацией GC, совсем не обязательно будет хорошо работать с другой.
Третья проблема от огромных лозунгов, что все проблемы с управлением памятью и иже с ними временем жизни и владением — решены GC. GC решена только проблема управлением памятью. А время жизни и владение, как были одними из сложных проблем разработки ПО, так ими и остались. И эти моменты по прежнему надо продумывать и контролировать вручную.
Какие мысли?
12.09.07 03:28: Перенесено из 'Архитектура программного обеспечения'
Здравствуйте, WolfHound, Вы писали:
WH>ЗЫ А вобще логика офигенная: ГЦ плохо по тому что у меня руки кривые.
Нет, логика такая — GC плох потому, что он жрет мозг. И самая главная подлость GC — он делает это так незаметно, что жертва GC, сама того не сознавая, начинает молиться на него, воздавать хвалы и выполнять ритуальные жертвоприношения.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, eao197, Вы писали:
E>при использовании GC выделение памяти обходится (по слухам) дешевле C-шных malloc-ов, а освобождается затем всем скопом,
В C++ тоже можно создать много структур, а потом освободить их всех одним махом. При этом вполне можно обойтись без хитрых алгоритмов сборки мусора. Правда есть одна тонкость: каждая структура должна иметь тривиальный деструктор, чтобы его можно было не вызывать.
Вот несколько примеров.
Глава 10. Управление памятью
… 10.4. Размещение объекта в памяти
…
Для конкретной арены operator new() можно определить так:
void* operator new(size_t s, fast_arena& a)
{
return a.alloc(s);
}
а использовать следующим образом:
void f(fast_arena& arena)
{
X* p = new(arena) X; // распределить X на арене
// ...
}
Здесь предполагается, что fast_arena — это класс, который имеет функцию-член alloc(), применяющуюся для выделения памяти. Например:
class fast_arena {
// ...char* maxp;
char* freep;
char* expand(size_t s); // получить дополнительную память от
// распределителя общего назначенияpublic:
void* alloc(size_t s) {
char* p = freep;
return ((freep += s) < maxp) ? p : expand(s);
}
void free(void*) { } // ничего не делает
clear(); // освободить всю выделенную память
};
Такая арена специально предназначена для быстрого выделения памяти и почти мгновенного её освобождения. Важной областью применения арен является предоставление специальной семантики управления памятью.
10.5. Проблемы освобождения памяти
…
Идеальный вариант — тот, при котором пользователю вообще не нужно освобождать память, занятую объектом. Для этого, в частности, применяются специальные арены. Арену можно определить так, что в некоторой известной точке программы будет освобождаться вся память, занятая этой программой. Можно также написать для неё сборщик мусора. Первый подход очень распространён, второй — нет. Специальный сборщик мусора должен быть написан удачно, иначе проще встроить в программу стандартный [Boehm, 1993].
2. JPEG lib, файл jpeg-6b\structure.doc:
*** Memory manager services ***
…
In all cases, allocated objects are tied to a particular compression or decompression master record, and they will be released when that master record is destroyed.
The memory manager does not provide explicit deallocation of objects. Instead, objects are created in "pools" of free storage, and a whole pool can be freed at once. This approach helps prevent storage-leak bugs, and it speeds up operations whenever malloc/free are slow (as they often are). The pools can be regarded as lifetime identifiers for objects. Two pools/lifetimes are defined:
* JPOOL_PERMANENT lasts until master record is destroyed
* JPOOL_IMAGE lasts until done with image (JPEG datastream)
Когда-то, во времена зарождения языка C, его распределитель памяти был самым слабым из существующих. Это был алгоритм «первый попавшийся», то есть он работал следующим образом: распределитель просматривал все узлы в списке блоков памяти, и первый же попавшийся свободный блок, который был не меньше нужного размера, разбивался на две части — одна возвращалась по запросу, вторая (общий размер блока минус запрошенный размер) возвращалась в список свободных узлов. «Преимущества» этого очевидны — очень низкая скорость работы и дикая фрагментация памяти. В действительности это хуже, чем вы можете себе представить. При выделении памяти приходилось пробегать весь список блоков, игнорируя уже выделенные. Поэтому при увеличении числа блоков производительность падала, а блоки становились всё меньше и были непригодны к использованию. Они отнимали время без всякой реальной пользы.
…
Я сходил в свой кабинет, где лежала копия книги IDL, принёс её с собой назад, и открыл главу «Распределение памяти».
…
«Я написал эту главу, в которой рассказывается о разработке высокопроизводительного, минимально фрагментирующего распределителя памяти.»
…
Распределитель памяти в NT работает весьма схожим образом с тем, что я описал в книге IDL, и основан на алгоритме «быстрого совпадения», разработанном Чаком Вейнстоком для его докторской в CMU около 1974 года.
3. Распределитель памяти в Quake 2. Файл quake2-3.21\qcommon\common.c:
// memory tags to allow dynamic memory to be cleaned up#define TAG_GAME 765 // clear when unloading the dll#define TAG_LEVEL 766 // clear when loading a new level
Здравствуйте, McSeem2, Вы писали:
MS>GC плох потому, что он жрет мозг. И самая главная подлость GC — он делает это так незаметно, что жертва GC, сама того не сознавая, начинает молиться на него, воздавать хвалы и выполнять ритуальные жертвоприношения.
Какая страшная история. А компилятор тоже жрет мозг?
... << RSDN@Home 1.2.0 alpha rev. 746>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Здравствуйте, Sinclair, Вы писали:
S>Я так не думаю. Без поддержки платформы состряпать свои делегаты, мягко говоря, трудно. Вряд ли удастся обеспечить ковариантность, и будут проблемы с быстродействием.
Разработчики Немерле и как я понимаю Скала + F# c этим справились.
Тут вопрос в другом даже. Делегаты сами по себе безграмотно спроектированы. В них:
1. Ошибочно заложена поддержка списка фунций, что перебор для большинства применений (кроме событий).
2. Они задают уникальный тип и получается, что два делегата с одной сигнатурой несовместимы между собой.
Вместо делегатов нужно было реализовать функциональный тип. Он должен описываться только сигнатурой и позволять ссылатьс ятолько на одну функцию. Если кому-то нужно создать список ссылок на фунции, то его можно поместить в массив или List<функциональный тип>.
А вот для создания уникальных типов в язык или платформу нужно было бы ввести "строгий" typedef. Типа:
type T1 = int;
T1 a = 1;
int b = a; // Ошибка времени компиляции!
В прочем, вопрос нужно ли было в событиях применять строгие типы тоже очень спорный. Хотя сама фича полезна для усиления контроля типов компилятором, ведь скажем метры и градусы можно легко перепутать.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
<...информация прочитана, усвоена и почикана...>
R>Какие мысли?
Главная мысль в том, что перечисленные тобой случаи можно назвать граничными условиями использования GC. Да, в них GC становится одним из условий решаемой задачи, поскольку нужно принимать в расчет его возможные (и невозможные) фокусы.
Но с другой стороны, есть масса очень простых случаев, когда GC берет на себя заботы программиста. Тем самым упрощая разработку и снижая количество ошибок. А если учесть, что при использовании GC выделение памяти обходится (по слухам) дешевле C-шных malloc-ов, а освобождается затем всем скопом, то GC может привести (и приводит, по benchmark-ам по крайней мере) к увеличению скорости работы программы на некоторых задачах.
Так что, если вспомнить закон потребления пива 20/80, то GC является отличным инструментом в 80% случаев. Зато в оставшихся 20% с ним придется бороться.
Явное же управление памятью наоборот, вызывает лишние затраты в 80% случаев, зато в 20% это именно то, что нужно.
Справедливости ради нужно сказать, что в C++, к счастью, есть возможность создавать объекты на стеке и передавать их по значению. Что часто очень серьезно снижает количество операций new/delete.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, GlebZ, Вы писали:
E>>А то, о чем ты написал -- это просто неподходящий алгоритм выделения памяти для конкретной задачи. Непосредственно к проблеме явного управления памяти он, имхо, не имеет отношения. GZ>Отчего же. GC — позволяет дефрагментировать память, и обходиться без прохода по спискам выделенных/пустых областей. То — что не умеет malloc. Так что замечание было в тему. ;)
Нет, не в тему. Алгоритмы распределения памяти с линейными списками благополучно начали дохнуть ещё в конце 80-х и окончательно сдохли к середине 90-х по причине того, что проход по спискам безнадёжно замусоривал кэши процессоров. Все новые алгоритмы в этот период писались уже с построением деревьев занятости и структурами для оптимизации поиска по желаемому размеру, а для мелких объектов — пулов фиксированного размера с внешними таблицами занятости (как правило, битовыми массивами). Сейчас же имеем ещё дополнительно 15 лет вылизывания этих алгоритмов.
Так что говорить, что malloc "не умеет" "обходиться без прохода по спискам выделенных/пустых областей" означает безнадёжно отставать от современного опыта, пользуясь данными не просто прошлого тысячелетия, а как минимум раннего допотопья.:) Признайтесь — Вы небось ни одну современную реализацию malloc не смотрели, а про списки областей вычитали где-нибудь в книгах написанных в лучшем случае в начале 80-х, а задуманных в конце 70-х? У Вирта? ;)))
E>>Что особо чувствительно для 24x7 процессов, которые месяцами не выгружаются и не останавливаются. GZ>Когда работал на С++, для серверов изначально не использовал STL по данной причине. Сейчас уже не знаю, по дурости или без. :-\ Поэтому сказать ничего не могу.
Видимо, таки по ней, родимой:) — иначе сложно назвать ориентирование на данные двадцатилетней давности.
Здравствуйте, eao197, Вы писали:
E>Я считал, что проблема фрагментации памяти для new/delete (malloc/free) заключается в другом. В том, что адресное пространство процесса постоянно растет. Что приводит к частым попаданиям мимо кэша или слишком частым вытеснениям занятых процессом страниц памяти в своп. Что особо чувствительно для 24x7 процессов, которые месяцами не выгружаются и не останавливаются.
Что-то не замечал подобного эффекта и плохо себе представляю, как его можно получить. Даже если реализация способна только забирать память у системы и не возвращать, а нагрузка постоянна (или колеблется с периодом значительно меньше набранного времени жизни процесса), то потребление памяти должно стабилизироваться на уровне немного большем, чем необходимо для держания всех данных. "Немного" зависит от разнообразия размера объектов и может быть хоть 1.5, но оно постоянно для шаблона потребления. Если же объём памяти постоянно растёт — это скорее признак какой-то утечки, нежели метода работы с памятью. Наблюдение за долгоживущими нагруженными серверами (из моих подопечных это innd, squid, ircd, netmond, sendmail, exim и так далее) подтверждает эту теорию.
О фрагментации имеет смысл говорить, если был пик нагрузки значительно выше обычного уровня (при котором действительно были проблемы кэша и свопа) и затем она упала до обычного уровня. В этом случае вполне вероятно иметь множество слабозаполненных страниц, в тяжёлом случае по 1-2 живых объекта на страницу. Но в любом случае такое растёт из прошлого всплеска.
Ряд программ реализует защиту от подобного использованием своего менеджера памяти, но не ради оптимизации по размеру или чему-то подобному, а ради возможности потом одной порцией устранить пул памяти, использованный, например, под обработку одного запроса:) Такие реализации лишены большей части проблем с недоиспользованием. Оборотная сторона — необходимость полностью контролировать выделение памяти в коде с использованием нужного менеджера — приводит к почти полной потере возможности использовать стандартные библиотеки. Шаблонные классы C++ с заданием аллокатора порождены именно подобной спецификой.
E>А то, о чем ты написал -- это просто неподходящий алгоритм выделения памяти для конкретной задачи. Непосредственно к проблеме явного управления памяти он, имхо, не имеет отношения.
Здравствуйте, remark, Вы писали:
R>Третья проблема от огромных лозунгов, что все проблемы с управлением памятью и иже с ними временем жизни и владением — решены GC. GC решена только проблема управлением памятью. А время жизни и владение, как были одними из сложных проблем разработки ПО, так ими и остались. И эти моменты по прежнему надо продумывать и контролировать вручную.
R>Какие мысли?
Я бы добавил сюда еще одну проблему -- GC прощает ошибки программиста. Несколько раз уже с подобными вещами сталкивался, но детали забывались. А вот сегодня сделал у себя в C++ ошибку, которая проявилась бы в языке с GC по другому.
Суть вот в чем: есть два map-а, ключами в которых являются идентификаторы клиентов, а значениями -- ссылки на соответствующие этим клиентам объекты (в данном случае фильтры). В одном map-е хранятся фильтры, которые еще не прошли подтверждение, а во втором -- уже подтвержденые. И есть операция switch_to_delayed_filter, которая перемещает фильтр из одного map-а в другой, возвращая указатель на фильтр:
filter_t *
channel_filters_t::switch_to_delayed_filter(
const client_id_t & id )
{
// Ищем отложенный фильтр в map-е еще не подтвержденных.
filter_map_t::iterator it = m_delayed.find( id );
if( it != m_delayed.end() )
{
// Перемещаем из одного map-а в другой.
filter_t * result = it->second.get();
m_actual.insert( *it );
m_delayed.erase( it );
return result;
}
else// Ну нет такого фильра, пускай наверху разбираются.return 0;
}
Ошибка состояла в том, что при некоторых стечениях обстоятельств для одного и того же id фильтры оказывались одновременно в m_actual и m_delay. И операция m_actual.insert() в этом случае ничего не делала. Соответственно, объект, на который указывает result уничтожался во время m_delayed.erase(). И switch_to_delayed_filter возвращает повисший указатель. Что приводит к краху приложения.
Собственно, это явилось следствием другой более важной ошибки: не должно быть одинакового id в m_actual и m_delayed в одно и то же время. Но, в конце-концов приложение просто свалилось и это заставило меня найти все причины.
А в случае с GC объект result содержал бы валидную ссылку. И оказалось бы, что switch_to_delayed_filter возвращает совсем не тот фильтр, который находится в m_actual. И ничего бы не падало. Просто работало бы не так как нужно. И еще не понятно, когда бы все всплыло, ведь в тестах у меня все клиенты использовали одинаковые фильтры
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, remark, Вы писали:
VD>>>ОК. Тогда зачем вся эта тема? Ну, какова ее цель? Ведь конкретные люди сталкивались с конкретными проблемами и при работе с кучей С/С++. Почему ты не посвятил свою тему этому?
R>>А почему я не посвятил свою тему арбузам? Многим бы было интересно. R>>А почему ты не посвящаешь свои темы организации кэшей современных процессоров? Мне было бы интересно! R>>Или тут можно постить только по квотам от тебя?
VD>Так ответ на мой вопрос будет? Или дальше продолжишь заниматься демагогией?
Я не посвятил свой пост проблемам с кучей С/С++, просто потому что я посвятил свой пост другой теме. А посвящать посты всему я просто не могу.
Здравствуйте, Cyberax, Вы писали:
C>Я вот лично не знаю как сделать полный аналог Boost.Interprocess без ручного управления памятью. Хотя как GC работают я знаю в деталях.
Я так понял это куча контейнеров которые шарятся между процессами?
А нафига?
Лично у меня никогда даже жилания не возникало.
Я даже между потоками стараюсь шарить только неизменяемые структуры данных.
А шарить между процессами изменяемые звучит как полная дичь.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, FR, Вы писали:
PD>>Кстати, то же относится к деструктированию объектов. Почему бы не сделать так, чтобы программист мог либо поручить это GC, либо сказать — делай детерминированно сейчас ?
FR>В D есть и RAII и GC и полное ручное управление (переопределяймы new)
PD>>Никаких принципиальных причин, почему это невозможно, я не вижу (если кто видит — скажите). Конечно, в нынешние языки и системы это не лезет. Может, пора новый язык/систему создать с такими возможностями.
FR>Уже есть, при том язык вполне близкий к C++.
Имхо, сейчас это "есть" определяется всего лишь наличием dsource.org и высоким рейтингом D в индексе TIOBE. А с учетом того, что разработчики не стабилизировав и не доведя до ума D1.0 затеяли долгий путь в неизвестность под названием D2.0 -- его присутствие становится, имхо, виртуальным.
Касательно данной темы, в D попыткой внедрить в C/C++ семейство сборщик мусора насыпали довольно много мелких камешков для программистов. Наличие примитивных типов (value types), структур (опять value types), классов (reference types) и на все это ссылок и указателей затрудняет восприятие языка (и программирование на шаблонах). А попытка навесить на все это константность делает ситуацию еще хуже.
Так что эксперимент по сочетанию в D ручного управления памятью и сборщика мусора еще только развивается и о результатах следить рановато.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Pavel Dvorkin, Вы писали: PD>Спасибо, а то я не слышал до сих пор об этом. Только это уже не совсем value ИМХО
Вполне себе совсем. Вместе с оснасткой, необходимой для успешного существования в куче. S>>Во-вторых, ссылочный тип в стеке разместить нельзя по принципиальным соображениям: ссылка на такой объект может пережить разрушение фрейма стека и окажется повисшей. А GC собственно придуман для гарантии ссылочной целостности. PD>Неубедительно. Я не говорю о C# и .Net, но можно представить себе среду, в которой для ссылок на объекты в стеке при разрушении фрейма стека автоматически вызывается "деструктор". Ее кстати и придумывать не надо — C++ unmanaged.
Ничего подобного в C++ unmanaged нету. Вернуть ссылку на стековый объект в нем — как четыре байта переслать. PD>Вот с этим я не знаком. Судя по всему, это аналог того же самого, что и в C++.
Нет. Ничего подобного в С++ нету. Никаким анализом компилятор не занимается, если написал new — будет тебе new. Разница между автоматическим анализатором, принимающим решение, можно ли разместить конкретный экземпляр в стеке, и компилятором, который умнее инлайнинга ничего не делает, понятна невооруженным мозгом.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, remark, Вы писали: R>>Многие считают, что среда с GC предоставляет многопоточную безопасность в сильном смысле (захват объекта, если ещё нет ссылки на него). GC этого *не* предоставляет. Он предоставляет только *базовую* многопоточную безопасность.
R>>Читаем ещё раз здесь R>>И думаем над исключением 'Disposed object cannot be accessed' S>Думать тут нечего. Никакого отношения к GC это не имеет. Поясняю еще раз на пальцах: GC обеспечивает только управление памятью. Он не обеспечивает никакого управления состоянием объекта. S>В частности, с этим связаны интересные эффекты в самодельных синглтонах, когда "более шустрый второй поток" успевает выхватить свежесозданный синглтон из рук первого потока, и начать терзать его не дожидаясь инициализации. S>В частности, с этим связаны спецэффекты с формами, которые уже отдиспозены к моменту обращения к ним из другого потока. S>Это совершенно неважно. Если ты удерживаешь ссылку на IDisposable объект, надо быть всегда готовым к тому, что он может неожиданно задиспозиться. Даже в однопотоковом приложении. S>Тем не менее, объект всё еще будет "жив" в том смысле, что его память будет принадлежать именно ему.
Чем не "указатель на удаленный объект"? За исключением терминологии и деталей?
Происходит нарушение защиты памяти, расстрел памяти или исключение не суть важно.
Здравствуйте, VladD2, Вы писали:
VD>GC не иделное решене. У него есть проблемы. Одна из главных проблем — это увеличение потребности в памяти. GC работает эффективно только при наличии запаса свободной памяти. Он как бы меняет лишнюю память на автоматическое упрваление ею.
Ты знаешь, Влад, ты мой лучший враг в спорах, но здесь я с тобой соглашусь. Ты прав. Ты растешь! Это ценно. Было особенно интересно узнать про хэш-таблицу, в которой все хеш-значения были одинаковыми. Это же был фактически exhaustive search! Вообще удивительно как все продолжало хоть как-то работать. Вот в этом-то и заключается главный недостаток GC — он жрёт мозг.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Sinclair wrote: > A>На слабых ссылках нужно было это делать. Было бы помедленнее, но зато > не нужно заботиться от отписывании. > Есть реализации делегатов на слабых ссылках; но встраивать слабость > делегатов в платформу, имхо, спорный вариант.
Более сильный вариант: встраивать делегаты в платформу — спорный вариант
(ИМХО).
Здравствуйте, remark, Вы писали:
R>Неожиданное исчерпание свободной памяти. R>Возникает при использовании пиннинга памяти. Не обязательно явном. Например при использовании асинхронного ввода-вывода ран-тайм скорее всего сам будет делать пиннинг памяти. В CLI такая возможность так же присутствует в явном виде, в Java — не знаю. Суть пиннинга — запрещение перемещения объекта в памяти. Это может препятствовать "уплотнению" используемой памяти во время сборки мусора, таким образом используемая память будет сильно фрагментирована и "кпд" использования памяти резко снижается. R>Здесь можно прочитать более подробно. Кратко суть такая: в C# при использовании асинхронных сокетов (IOCP) в сервере заканчивалось 3GB памяти (летели OutOfMemoryException), хотя "полезных" данных в памяти было примерно 200MB.
Проблема была вызвана кривым решением в CLR. На сегодня она исправлена (если не ошибаюсь во Фрэймворке 2.0 ее уже нет).
Ввывод — это не проблема GC в общем, а проблема конкретной реализации.
R>Постепенная и периодическая деградация производительности и рост используемой памяти под нагрузкой. R>Подробности здесь. Кратко: в Java при использовании WeakHashMap и включении Concurrent GC вместо штатного начали проявляться упомянутые эффекты. Оказалось, что под нагрузкой большую часть элементов WeakHashMap постоянно "трогают", хотя реально не используют. Это "троганье" предотвращало удаление каких-либо объектов из WeakHashMap вообще. Соответственно он неограниченно рос, пока весь сервер не затыкался на некоторое время. Во время затыкания элементы WeakHashMap никто не "трогал", и соотв. они все удалялись. Все становится хорошо. А потом по новой. Со штатным GC такой эффект не наблюдается.
Опять же... Сам говришь, что проблема проявляется только с кокретной реализацией GC. Значит и это проблема реализации.
R>Ну более-менее стандартная проблема с временем жизни и владением объектами. R>Многие по началу считают, что при наличии GC этих проблем просто нет. К сожалению это не так. GC обеспечивает только базовую потокобезопасность для ссылок (можно захватывать новые ссылки на объект, только если у тебя уже есть хотя бы одна), но не обеспечивает строгой потокобезопасности для ссылок (возможность захватывать новые ссылки на объект, если у тебя ещё нет ни одной). Т.о. если необходима строгая потокобезопасность, то — мьютекс + счётчик ссылок... Что-то мне это напоминает... R>Один из примеров можно поглядеть здесь
Ни Ява, ни дотнет не содержат серьзных средств упрощающих многопоточную разработку. GC тут просто не причем. Более того есть системы с GC которые как раз радикально упрощают разработку многопточных систем (Эрлэнг, Сингулярити и т.п.).
R>Какие мысли?
Мысль одна. Не следует обсуждать слухи. А уж если полез обсуждать, то разберись в проблематике.
GC не иделное решене. У него есть проблемы. Одна из главных проблем — это увеличение потребности в памяти. GC работает эффективно только при наличии запаса свободной памяти. Он как бы меняет лишнюю память на автоматическое упрваление ею.
Кроме того GC сам по себе не предоставляет средств управления другими ресурсами и выявления проблем с неосвобождением памяти (складыванием ее в кучу). Однако эти проблемы могут быть решены отладчиками, языками программирования и инструментальными средствами.
Ну, а описанные здесь "проблемы" не более чем громкие охания.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, remark, Вы писали:
R>Возникает при использовании пиннинга памяти. Не обязательно явном. Например при использовании асинхронного ввода-вывода ран-тайм скорее всего сам будет делать пиннинг памяти. В CLI такая возможность так же присутствует в явном виде, в Java — не знаю. Суть пиннинга — запрещение перемещения объекта в памяти. Это может препятствовать "уплотнению" используемой памяти во время сборки мусора, таким образом используемая память будет сильно фрагментирована и "кпд" использования памяти резко снижается.
pinning — это unsafe операция. А unsafe поэтому и называется unsafe, что вполне можно загасить GC, или сделать другие пакости типа обращение по невалидному указателю. Никто не обещал кайфа при unsafe (как и при работе с unmanaged ресурсами). То что 90 процентов(и может быть больше) обычной программы — это чистые managed типы где можно забыть про деструктор — это и есть успех GC.
R>Здесь можно прочитать более подробно. Кратко суть такая: в C# при использовании асинхронных сокетов (IOCP) в сервере заканчивалось 3GB памяти (летели OutOfMemoryException), хотя "полезных" данных в памяти было примерно 200MB.
Это просто бага. Притом бага не GC — а использования unsafe.
R>Кратко: в Java
Не буду высказываться — подробности GC в Java — мне неизвестны.
R>Многие по началу считают, что при наличии GC этих проблем просто нет. К сожалению это не так. GC обеспечивает только базовую потокобезопасность для ссылок (можно захватывать новые ссылки на объект, только если у тебя уже есть хотя бы одна), но не обеспечивает строгой потокобезопасности для ссылок (возможность захватывать новые ссылки на объект, если у тебя ещё нет ни одной).
Не понял? Статический конструктор действительно не потокобезопасен. Но это легко обходится. R>Т.о. если необходима строгая потокобезопасность, то — мьютекс + счётчик ссылок... Что-то мне это напоминает...
Не нужен подсчет ссылок. R>Один из примеров можно поглядеть здесь
Плохой пример. Это работа с unmanaged. К тому же ответ сильно удивил. Если очень интересно то на форме есть метод Disposing/ event Disposed. Можно вполне понять когда unmanaged handle HWND был закрыт.
R>Первые две проблемы от того, что GC хотят сделать полностью прозрачным и скрытым от программиста, типа он просто магически работает. К сожалению, полностью прозрачен он только на абстрактном уровне. Когда дело доходит до самых деталей начинается самое интересное — побочные эффекты GC становятся видны. Отсюда ещё одно неприятное следствие — программа хорошо работающая с одним типом или даже скорее реализацией GC, совсем не обязательно будет хорошо работать с другой.
Именно поэтому в принципе в Net — один тип GC(в действительности два). И скрыто потому, что выделением/невыделением каких-то объектов ты лучше можешь управлять производительностью чем редактированием самих параметров GC.
R>Третья проблема от огромных лозунгов, что все проблемы с управлением памятью и иже с ними временем жизни и владением — решены GC. GC решена только проблема управлением памятью. А время жизни и владение, как были одними из сложных проблем разработки ПО, так ими и остались.
Для managed objects — решены. А их подавляющее большинство. R>И эти моменты по прежнему надо продумывать и контролировать вручную.
А для этого и есть Dispose Pattern. Не слишком хорошая вещь — но работает.
R>Какие мысли?
Не убедил.
Здравствуйте, GlebZ, Вы писали:
E>>Если чесно, то никогда с этой проблемой на практике не сталкивался. GZ>Сталкивался. Было много мелких объектов, алгоритм должен был быть очень быстрым. При выделении памяти — стандартный malloc проходил по всей цепочке пытаясь найти место, в результате проседала производительность. Пришлось переопределять new, и делать свой менеджер памяти. Примерно такая-же ситуация была с VirtualAlloc(работает по тому же принципу). GZ>Кто-то писал, что в САПР переопределение стандартного менеджера памяти было необходимо(по тем же причинам).
GZ>Так что бывает.
Я считал, что проблема фрагментации памяти для new/delete (malloc/free) заключается в другом. В том, что адресное пространство процесса постоянно растет. Что приводит к частым попаданиям мимо кэша или слишком частым вытеснениям занятых процессом страниц памяти в своп. Что особо чувствительно для 24x7 процессов, которые месяцами не выгружаются и не останавливаются.
А то, о чем ты написал -- это просто неподходящий алгоритм выделения памяти для конкретной задачи. Непосредственно к проблеме явного управления памяти он, имхо, не имеет отношения.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Я считал, что проблема фрагментации памяти для new/delete (malloc/free) заключается в другом. В том, что адресное пространство процесса постоянно растет. Что приводит к частым попаданиям мимо кэша или слишком частым вытеснениям занятых процессом страниц памяти в своп.
Та программа была под Dos и выполнялась на 286/386 машинах. Так что не было ни кэша, ни свопа.
E>Что особо чувствительно для 24x7 процессов, которые месяцами не выгружаются и не останавливаются.
Когда работал на С++, для серверов изначально не использовал STL по данной причине. Сейчас уже не знаю, по дурости или без. Поэтому сказать ничего не могу.
E>А то, о чем ты написал -- это просто неподходящий алгоритм выделения памяти для конкретной задачи. Непосредственно к проблеме явного управления памяти он, имхо, не имеет отношения.
Отчего же. GC — позволяет дефрагментировать память, и обходиться без прохода по спискам выделенных/пустых областей. То — что не умеет malloc. Так что замечание было в тему.
Здравствуйте, rsn81, Вы писали:
R>Здравствуйте, eao197, Вы писали:
E>>Справедливости ради нужно сказать, что в C++, к счастью, есть возможность создавать объекты на стеке и передавать их по значению. Что часто очень серьезно снижает количество операций new/delete. R>В Java SE 6 реализован т.н. Escape-анализ: вумный JIT может принять решение о выделении памяти под объекты на стеке, нежели массиве — так что стек (неявно, конечно) доступен и в GC-средах.
Речь шла не о том, что в управляемых средах нет стека, а о том, что в C++ стековые объекты и объекты по значению значительно уменьшают использование new/delete, что приводит к уменьшению проблем с явным управлением памятью.
А в Java, что есть стек, что его нет, как создавались все объекты через new, так и создаются.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Пётр Седов, Вы писали:
ПС>Здравствуйте, eao197, Вы писали:
E>>при использовании GC выделение памяти обходится (по слухам) дешевле C-шных malloc-ов, а освобождается затем всем скопом, ПС>В C++ тоже можно создать много структур, а потом освободить их всех одним махом. При этом вполне можно обойтись без хитрых алгоритмов сборки мусора. Правда есть одна тонкость: каждая структура должна иметь тривиальный деструктор, чтобы его можно было не вызывать. ПС>Вот несколько примеров.
<...примеры поскипаны...>
Все это так, но это все меняет код программы или требует каких-то специальных условий. В то время как GC оставляет текст программы в первоначальном виде (как были new, так и остались, вне зависимости от расположения объектов в хипе или на стеке).
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>У меня на все это одна мысль возникла. А почему бы авторам некоей системы программирования не совместить GC и не-GC в одной коробке ? То есть ввести в систему GC и его управление памятью, но в то же оставить и возможность выделять/освобождать память вручную.
Здравствуйте, Pavel Dvorkin, Вы писали: PD>Вдогонку. А кстати, почему в C# жестко привязали тип объектов (object или value) к способу размещения (куча или стек). Почему нельзя value разместить в куче или object в стеке ? Это принципиально или просто особенность реализации ?
Во-первых, value в куче разместить можно. RTFM "Boxing".
Во-вторых, ссылочный тип в стеке разместить нельзя по принципиальным соображениям: ссылка на такой объект может пережить разрушение фрейма стека и окажется повисшей. А GC собственно придуман для гарантии ссылочной целостности.
Обратное также верно: если ни одна ссылка на объект не может пережить разрушения соответствующего фрейма стека, то объект таки можно разместить в стеке. В новой джаве это реализовано; RTFM "Escape Analysis".
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, remark, Вы писали:
R>Приемущество "Сишных" malloc/free в данном контексте — они просты как 2 копейки. В них просто нет ничего, что могло бы вообще вызывать какие-либо нарекания, или какие-либо проблемы. Именно они сами, не то, как их использовать. R>Я не помню, что бы слышал какие либо нарекания именно в адрес самих malloc/free. Да, это низкоуровневое средство. И оно хорошо делает одну чётко определённую вещь...
Ну, услышь: в условиях многопоточности, если куча не lock-free, можно на ровном месте поймать инверсию приоритетов — и, соответственно, внезапную просадку производительности.
В реалтайме это очень раздражает.
Здравствуйте, Кодт, Вы писали:
R>>Приемущество "Сишных" malloc/free в данном контексте — они просты как 2 копейки. В них просто нет ничего, что могло бы вообще вызывать какие-либо нарекания, или какие-либо проблемы. Именно они сами, не то, как их использовать. R>>Я не помню, что бы слышал какие либо нарекания именно в адрес самих malloc/free. Да, это низкоуровневое средство. И оно хорошо делает одну чётко определённую вещь...
К>Ну, услышь: в условиях многопоточности, если куча не lock-free, можно на ровном месте поймать инверсию приоритетов — и, соответственно, внезапную просадку производительности. К>В реалтайме это очень раздражает.
Поэтому в реалтайме стараются динамической памятью не пользоваться. И чем жесче рилтайм, тем больше стараются. Вплоть до полного отрицания динамической памяти как явления
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, remark, Вы писали: R>Многие считают, что среда с GC предоставляет многопоточную безопасность в сильном смысле (захват объекта, если ещё нет ссылки на него). GC этого *не* предоставляет. Он предоставляет только *базовую* многопоточную безопасность.
R>Читаем ещё раз здесь R>И думаем над исключением 'Disposed object cannot be accessed'
Думать тут нечего. Никакого отношения к GC это не имеет. Поясняю еще раз на пальцах: GC обеспечивает только управление памятью. Он не обеспечивает никакого управления состоянием объекта.
В частности, с этим связаны интересные эффекты в самодельных синглтонах, когда "более шустрый второй поток" успевает выхватить свежесозданный синглтон из рук первого потока, и начать терзать его не дожидаясь инициализации.
В частности, с этим связаны спецэффекты с формами, которые уже отдиспозены к моменту обращения к ним из другого потока.
Это совершенно неважно. Если ты удерживаешь ссылку на IDisposable объект, надо быть всегда готовым к тому, что он может неожиданно задиспозиться. Даже в однопотоковом приложении.
Тем не менее, объект всё еще будет "жив" в том смысле, что его память будет принадлежать именно ему.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, remark, Вы писали:
R>Чем не "указатель на удаленный объект"? За исключением терминологии и деталей?
Всем. Вместо слова "удаленный" можно также использовать "приближенный", "окрашенный", "изогнутый" и прочие прилагательные, характеризующие состояние.
Если ваше подсознание протестует против того, чтобы объект, ссылку на который удерживает ваш код, оказался disposed, выбросьте ваше подсознание.
Вот простейший пример неожиданного поведения:
public class Formatter
{
public string Format
{
set { _format = value; }
}
}
private string _format;
public string DoFormat(object a, object b)
{
return string.Format(_format, a, b);
}
public static Formatter F = new Formatter();
}
Вот код потока 1:
public string AundB(int a, int b)
{
Formatter.F.Format = "{0} + {1}";
return Formatter.F.DoFormat(a, b);
}
Если в это время поток 2 выполнит Formatter.F.Format = null, получим NPE. За исключением терминологии и деталей это то же самое, что и описываемое в статье поведение. Кто ожидал, что от этого NPE защитит GC, поднимите руки! А?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, remark, Вы писали:
R>Чем не "указатель на удаленный объект"? За исключением терминологии и деталей? R>Происходит нарушение защиты памяти, расстрел памяти или исключение не суть важно.
Дьявол в мелочах. В одном случае получаем аборт приложения в другом ловим исключение, обрабатываем его, логируем и при завершении, по крайней мере, пытаемся вернуть окружающую среду "как было".
R>>>Я не помню, что бы слышал какие либо нарекания именно в адрес самих malloc/free. GZ>>Дефрагментация.
видмо, всё же фрагментация
E>Если чесно, то никогда с этой проблемой на практике не сталкивался.
а я вот сталкиваюсь каждвый жень. бразуер запущен постоянно, в нём открываешь одни окна, закрываешь другие. в резудльтате обзийц обхём открытых данных остаётся примерно постоянным, а память течёт
Здравствуйте, remark, Вы писали:
VD>>ОК. Тогда зачем вся эта тема? Ну, какова ее цель? Ведь конкретные люди сталкивались с конкретными проблемами и при работе с кучей С/С++. Почему ты не посвятил свою тему этому?
R>А почему я не посвятил свою тему арбузам? Многим бы было интересно. R>А почему ты не посвящаешь свои темы организации кэшей современных процессоров? Мне было бы интересно! R>Или тут можно постить только по квотам от тебя?
Так ответ на мой вопрос будет? Или дальше продолжишь заниматься демагогией?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
[]
VD>ОК. Тогда зачем вся эта тема? Ну, какова ее цель? Ведь конкретные люди сталкивались с конкретными проблемами и при работе с кучей С/С++. Почему ты не посвятил свою тему этому?
Про проблемы с кучей с++ написано уже достаточно. А вот про проблемы с гц видимо не очень. Про гц принято писать, в основном, только в радужных тонах (только не тыкай меня в свою статью, где об этих неприятных эффектах упоминается).
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, remark, Вы писали: R>>Спасибо. R>>Вывод как я понял следующий. Там были [не очень] неявные ссылки между объектами, которые заставляли зависать в памяти очень большое дерево объектов. S>Я так понял, что проблема близка к знаменитой беде с делегатами в .Net. Позволю себе напомнить, что неаккуратная подписка объекта на событие завешивает его в памяти навсегда. S>Прелесть в том, что раз ссылок, кроме делегата, на объект нету, то шансов на отписку ~0.
А можешь пример привести, как можно неаккуратно подписаться на событие.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, remark
E><...информация прочитана, усвоена и почикана...>
R>>Какие мысли?
E>Главная мысль в том, что перечисленные тобой случаи можно назвать граничными условиями использования GC. Да, в них GC становится одним из условий решаемой задачи, поскольку нужно принимать в расчет его возможные (и невозможные) фокусы.
Я думаю, тут всё зависит от масштаба и уровня приложения.
В крупном/серьёзном/развиваемом продукте такие "граничные условия" скорее всего рано или поздно появятся. Дальше будет основной вопрос — возможно ли их вообще обойти при использовании выбранных технических средств? ...
E>Но с другой стороны, есть масса очень простых случаев, когда GC берет на себя заботы программиста. Тем самым упрощая разработку и снижая количество ошибок. А если учесть, что при использовании GC выделение памяти обходится (по слухам) дешевле C-шных malloc-ов, а освобождается затем всем скопом, то GC может привести (и приводит, по benchmark-ам по крайней мере) к увеличению скорости работы программы на некоторых задачах.
Я думаю, не стоит развивать эту тему дальше... Каждый может сразу представить к чему это приведёт и сразу просто остаться при своём мнении
E>Так что, если вспомнить закон потребления пива 20/80, то GC является отличным инструментом в 80% случаев. Зато в оставшихся 20% с ним придется бороться.
E>Явное же управление памятью наоборот, вызывает лишние затраты в 80% случаев, зато в 20% это именно то, что нужно.
Да. Если ты пишешь только 80%. Если же ты пишешь и оставшиеся 20%, и соотв. у тебя есть решения для этих 20%, то не вижу смысла не применять их в других 80%. Точнее так — я не вижу больше проблемы.
E>Справедливости ради нужно сказать, что в C++, к счастью, есть возможность создавать объекты на стеке и передавать их по значению. Что часто очень серьезно снижает количество операций new/delete.
В C# тоже есть "структуры", которые создаются на стеке и передаются по значению.
Приемущество "Сишных" malloc/free в данном контексте — они просты как 2 копейки. В них просто нет ничего, что могло бы вообще вызывать какие-либо нарекания, или какие-либо проблемы. Именно они сами, не то, как их использовать.
Я не помню, что бы слышал какие либо нарекания именно в адрес самих malloc/free. Да, это низкоуровневое средство. И оно хорошо делает одну чётко определённую вещь...
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, remark, Вы писали:
R>>Я не помню, что бы слышал какие либо нарекания именно в адрес самих malloc/free. GZ>Дефрагментация.
Если чесно, то никогда с этой проблемой на практике не сталкивался.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Если чесно, то никогда с этой проблемой на практике не сталкивался.
Сталкивался. Было много мелких объектов, алгоритм должен был быть очень быстрым. При выделении памяти — стандартный malloc проходил по всей цепочке пытаясь найти место, в результате проседала производительность. Пришлось переопределять new, и делать свой менеджер памяти. Примерно такая-же ситуация была с VirtualAlloc(работает по тому же принципу).
Кто-то писал, что в САПР переопределение стандартного менеджера памяти было необходимо(по тем же причинам).
Здравствуйте, remark, Вы писали:
R>Здесь можно прочитать более подробно. Кратко суть такая: в C# при использовании асинхронных сокетов (IOCP) в сервере заканчивалось 3GB памяти (летели OutOfMemoryException), хотя "полезных" данных в памяти было примерно 200MB.
В Java для асинхронного и memory-mapped IO используются unmanaged-буфферы, которые располагаются отдельно от основной кучи. Пиннинг делается только для критичных по скорости кусков нативного кода.
R>Постепенная и периодическая деградация производительности и рост используемой памяти под нагрузкой. R>Подробности здесь. Кратко: в Java при использовании WeakHashMap и включении Concurrent GC вместо штатного начали проявляться упомянутые эффекты. Оказалось, что под нагрузкой большую часть элементов WeakHashMap постоянно "трогают", хотя реально не используют. Это "троганье" предотвращало удаление каких-либо объектов из WeakHashMap вообще.
Бывает. Поэтому необходимо понимание механизмов работы GC. Обычно поэтому всегда вдобавок к Concurrent GC (обычно это просто трехцветный GC) еще включают обычный stop-the-world GC.
Кстати, при должной аппаратной поддержке этой проблемы можно было бы избежать
R>Многие по началу считают, что при наличии GC этих проблем просто нет. К сожалению это не так. GC обеспечивает только базовую потокобезопасность для ссылок (можно захватывать новые ссылки на объект, только если у тебя уже есть хотя бы одна), но не обеспечивает строгой потокобезопасности для ссылок (возможность захватывать новые ссылки на объект, если у тебя ещё нет ни одной). Т.о. если необходима строгая потокобезопасность, то — мьютекс + счётчик ссылок... Что-то мне это напоминает... R>Один из примеров можно поглядеть здесь
В данном случае мьютекс+счетчик — плохое решение. Дело в том, что работать с формой можно безопасно только из одного потока. Нужно было замаршалить вызов в GUI-поток, тогда никаких гонок бы не было.
В Java, кстати, по умолчанию таймеры как раз и работают в GUI-потоке.
R>Какие мысли?
Примеры надо покрасивее придумать
Здравствуйте, GlebZ, Вы писали:
R>>Здесь можно прочитать более подробно. Кратко суть такая: в C# при использовании асинхронных сокетов (IOCP) в сервере заканчивалось 3GB памяти (летели OutOfMemoryException), хотя "полезных" данных в памяти было примерно 200MB. GZ>Это просто бага. Притом бага не GC — а использования unsafe.
Это абсолютно не бага. Это архитектурная несовместимость GC и асинхронного высокопроизводительного zero-copy ввода-вывода.
R>>Какие мысли? GZ>Не убедил.
Я ни в чём и не убеждал
GZ>С уважением, Gleb.
Здравствуйте, GlebZ, Вы писали:
E>>Если чесно, то никогда с этой проблемой на практике не сталкивался. GZ>Сталкивался. Было много мелких объектов, алгоритм должен был быть очень быстрым. При выделении памяти — стандартный malloc проходил по всей цепочке пытаясь найти место, в результате проседала производительность. Пришлось переопределять new, и делать свой менеджер памяти. Примерно такая-же ситуация была с VirtualAlloc(работает по тому же принципу). GZ>Кто-то писал, что в САПР переопределение стандартного менеджера памяти было необходимо(по тем же причинам).
Ну так и ГЦ можно считать эдаким PoolBasedAllocator
От ОС то он все равно ее функциями память получает
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, remark, Вы писали:
R>Это абсолютно не бага. Это архитектурная несовместимость GC и асинхронного высокопроизводительного zero-copy ввода-вывода.
Это исключительно из-за того что ОС не правильной системы.
Если бы ОС была правильной то никакой несовместимости бы небыло... оно бы еще и быстрее чем на классических ОС работало...
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
WolfHound wrote: > R>Это абсолютно не бага. Это архитектурная несовместимость GC и > асинхронного высокопроизводительного zero-copy ввода-вывода. > Это исключительно из-за того что ОС не правильной системы. > Если бы ОС была правильной то никакой несовместимости бы небыло... оно > бы еще и быстрее чем на классических ОС работало...
Я вот лично не знаю как сделать полный аналог Boost.Interprocess без
ручного управления памятью. Хотя как GC работают я знаю в деталях.
Здравствуйте, remark, Вы писали:
R>Постепенная и периодическая деградация производительности и рост используемой памяти под нагрузкой. R>Подробности здесь. Кратко: в Java при использовании WeakHashMap и включении Concurrent GC вместо штатного начали проявляться упомянутые эффекты. Оказалось, что под нагрузкой большую часть элементов WeakHashMap постоянно "трогают", хотя реально не используют. Это "троганье" предотвращало удаление каких-либо объектов из WeakHashMap вообще. Соответственно он неограниченно рос, пока весь сервер не затыкался на некоторое время. Во время затыкания элементы WeakHashMap никто не "трогал", и соотв. они все удалялись. Все становится хорошо. А потом по новой. Со штатным GC такой эффект не наблюдается.
В статье есть еще одно условие — hashCode() должна всегда возвращать одно и то же значение, тогда как equals() работать нормально. Естественно это баг, баг в програме, который приведёт к проседанию производительности при любом GC на любой Map. Просто обычный stop-the-world _маскировал_ эту проблему.
Что касается частого выбрасывания элементов из weak map при CGC, то, действительно, из программы крутилок никаких нету (в .Net, afair, крутилка доступна самой программе). Зато есть крутилка в sun jvm, которая позволяет продлить время жизни weak элемента, даже после того, как на него пропали ссылки. Другое дело, что когда пришло время эту крутилку попользовать, то оказалось, что на солярке, при той комбинации параметров, что давала лучшую производительность, эта крутилка игнорится. Сантехники баг починили за месяц, но осадочек остался.
R>Третья проблема от огромных лозунгов, что все проблемы с управлением памятью и иже с ними временем жизни и владением — решены GC.
Дык, эта. Неуправляемыми ресурсами нужно управлять самостоятельно.
R>Какие мысли?
По моему, этой теме ближе раздел философии, а не дизайна. Как-то ожидал увидеть рекомендации построения приложений так, чтобы обойти подводные камни, да не вижу.
Однажды приучившись явно управлять памятью непросто от этого избавиться. Так и хочется поуправлять.
А то что GC пытаются сделать прозрачным да незаметным -- это хорошо. Задачи разные есть, каждой задаче свой инструмент, и свой подход.
Здравствуйте, WolfHound, Вы писали:
C>>Я вот лично не знаю как сделать полный аналог Boost.Interprocess без ручного управления памятью. Хотя как GC работают я знаю в деталях. WH>Я так понял это куча контейнеров которые шарятся между процессами?
Между процессами или отображаемыми в память файлами.
WH>А нафига? WH>Лично у меня никогда даже жилания не возникало. WH>Я даже между потоками стараюсь шарить только неизменяемые структуры данных. WH>А шарить между процессами изменяемые звучит как полная дичь.
Одно слово: кэши.
Я с его помощью сделал почти прозрачное транзакционное disk-backed кэширование (операционная система еще и предоставляет кэширование в памяти). По скорости ничего даже близко не приближается.
Здравствуйте, Cyberax, Вы писали:
C>Между процессами или отображаемыми в память файлами.
Детали.
C>Одно слово: кэши.
Какие и сколько данных в кеше?
C>Я с его помощью сделал почти прозрачное транзакционное disk-backed кэширование (операционная система еще и предоставляет кэширование в памяти).
Транзакционное? Что-то както сомневаюсь.
В самом Boost.Interprocess нет упоминаний о транзакциях.
А самому их делать
C>По скорости ничего даже близко не приближается.
Тоже не факт.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, CreatorCray, Вы писали:
CC>Ну так и ГЦ можно считать эдаким PoolBasedAllocator
Нет. Процесс дефрагментации мешает его так назвать. CC>От ОС то он все равно ее функциями память получает
Вопрос в том, как использовать эту память.
Здравствуйте, WolfHound, Вы писали:
C>>Между процессами или отображаемыми в память файлами. WH>Детали.
Ну ты базу данных используешь? Так ведь она (О ужас!) тоже распределяется между процессами.
C>>Одно слово: кэши. WH>Какие и сколько данных в кеше?
32 мегабайта Это встроеное устройство.
C>>Я с его помощью сделал почти прозрачное транзакционное disk-backed кэширование (операционная система еще и предоставляет кэширование в памяти). WH>Транзакционное? Что-то както сомневаюсь. WH>В самом Boost.Interprocess нет упоминаний о транзакциях.
Там есть упоминания о мьютексах.
WH>А самому их делать
Совсем несложно — я и в обычном стиле почти так же пишу.
C>>По скорости ничего даже близко не приближается. WH>Тоже не факт.
Пробовал SQLite, MySQL и db4o. У меня быстрее всего работает, что совсем неудивительно.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, eao197, Вы писали:
E>>Я считал, что проблема фрагментации памяти для new/delete (malloc/free) заключается в другом. В том, что адресное пространство процесса постоянно растет. Что приводит к частым попаданиям мимо кэша или слишком частым вытеснениям занятых процессом страниц памяти в своп. GZ>Та программа была под Dos и выполнялась на 286/386 машинах. Так что не было ни кэша, ни свопа.
Да уж, представляю себе САПР под Dos-ом на 286 на менеджед языке со сборкой мусора
С тех пор не только железо лучше стало, но и алгоритмы malloc-а (dlmalloc, к примеру).
E>>Что особо чувствительно для 24x7 процессов, которые месяцами не выгружаются и не останавливаются. GZ>Когда работал на С++, для серверов изначально не использовал STL по данной причине. Сейчас уже не знаю, по дурости или без. Поэтому сказать ничего не могу.
Я использую, но вот с фрагментацией не сталкивался.
E>>А то, о чем ты написал -- это просто неподходящий алгоритм выделения памяти для конкретной задачи. Непосредственно к проблеме явного управления памяти он, имхо, не имеет отношения. GZ>Отчего же. GC — позволяет дефрагментировать память, и обходиться без прохода по спискам выделенных/пустых областей. То — что не умеет malloc. Так что замечание было в тему.
Линейный список блоков в аллокаторе -- это уже история. Я надеюсь
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Cyberax, Вы писали:
C>Ну ты базу данных используешь? Так ведь она (О ужас!) тоже распределяется между процессами.
Это ты вобще к чему?
C>32 мегабайта Это встроеное устройство.
Лично я кеши десятками гигабайт меряю...
Кстати, а зачем на встроеном устройстве кешь. Да еще и расшаренный между процессами.
C>Там есть упоминания о мьютексах.
И? С каких это пор мьютексы обеспечивают транзакции?
C>Совсем несложно — я и в обычном стиле почти так же пишу.
Я какбы писал код гарантирующий ACID.
C>Пробовал SQLite, MySQL и db4o. У меня быстрее всего работает, что совсем неудивительно.
Правильно. Там есть транзакции, а у тебя их нет.
По крайней мере ты так и не сказал откуда они взялись.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
C>>Ну ты базу данных используешь? Так ведь она (О ужас!) тоже распределяется между процессами. WH>Это ты вобще к чему?
Это про shared-данные.
C>>32 мегабайта Это встроеное устройство. WH>Лично я кеши десятками гигабайт меряю...
Это неинтересно. Туда можно и RAID-массив воткнуть и пару гигабайт памяти.
WH>Кстати, а зачем на встроеном устройстве кешь. Да еще и расшаренный между процессами.
Там есть несколько процессов, собирающих данные с разных устройств, процесс-обработчик и закачивальщик результата на центральный сервер.
И это все асинхронно работает.
C>>Там есть упоминания о мьютексах. WH>И? С каких это пор мьютексы обеспечивают транзакции?
Это у меня основной инструмент для их обеспечения.
C>>Совсем несложно — я и в обычном стиле почти так же пишу. WH>Я какбы писал код гарантирующий ACID.
А я писал ACID? У меня, на самом деле, ACI (без D — его дейстивительно сложно делать).
C>>Пробовал SQLite, MySQL и db4o. У меня быстрее всего работает, что совсем неудивительно. WH>Правильно. Там есть транзакции, а у тебя их нет.
Есть, с оптимистическим версированием. При коммите блокирую нужные объекты (мьютексами), проверяю версии и заливаю обновления.
Здравствуйте, Cyberax, Вы писали:
C>Это неинтересно. Туда можно и RAID-массив воткнуть и пару гигабайт памяти.
Восемь.
C>Там есть несколько процессов, собирающих данные с разных устройств, процесс-обработчик и закачивальщик результата на центральный сервер. C>И это все асинхронно работает.
По описанию идеально ложится на объмен сообщениями вобще и ОСь типа сингулярити в частности.
C>Это у меня основной инструмент для их обеспечения.
Ну то что без блокировок транзакции не сделать это и так ясно.
C>Есть, с оптимистическим версированием. При коммите блокирую нужные объекты (мьютексами), проверяю версии и заливаю обновления.
Те что-то типа STM?
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, eao197, Вы писали:
E>Справедливости ради нужно сказать, что в C++, к счастью, есть возможность создавать объекты на стеке и передавать их по значению. Что часто очень серьезно снижает количество операций new/delete.
В Java SE 6 реализован т.н. Escape-анализ: вумный JIT может принять решение о выделении памяти под объекты на стеке, нежели массиве — так что стек (неявно, конечно) доступен и в GC-средах.
Здравствуйте, netch80, Вы писали:
E>>Я считал, что проблема фрагментации памяти для new/delete (malloc/free) заключается в другом. В том, что адресное пространство процесса постоянно растет. Что приводит к частым попаданиям мимо кэша или слишком частым вытеснениям занятых процессом страниц памяти в своп. Что особо чувствительно для 24x7 процессов, которые месяцами не выгружаются и не останавливаются.
N>Что-то не замечал подобного эффекта и плохо себе представляю, как его можно получить. Даже если реализация способна только забирать память у системы и не возвращать, а нагрузка постоянна (или колеблется с периодом значительно меньше набранного времени жизни процесса), то потребление памяти должно стабилизироваться на уровне немного большем, чем необходимо для держания всех данных. "Немного" зависит от разнообразия размера объектов и может быть хоть 1.5, но оно постоянно для шаблона потребления. Если же объём памяти постоянно растёт — это скорее признак какой-то утечки, нежели метода работы с памятью. Наблюдение за долгоживущими нагруженными серверами (из моих подопечных это innd, squid, ircd, netmond, sendmail, exim и так далее) подтверждает эту теорию.
N>О фрагментации имеет смысл говорить, если был пик нагрузки значительно выше обычного уровня (при котором действительно были проблемы кэша и свопа) и затем она упала до обычного уровня. В этом случае вполне вероятно иметь множество слабозаполненных страниц, в тяжёлом случае по 1-2 живых объекта на страницу. Но в любом случае такое растёт из прошлого всплеска.
Об этом я и говорил. Наверноее выразился неудачно.
Тем более, что на практике с фрагментацией памяти я пока не встречался.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
<все skipped после чтения данного сообщения и ответов>
У меня на все это одна мысль возникла. А почему бы авторам некоей системы программирования не совместить GC и не-GC в одной коробке ? То есть ввести в систему GC и его управление памятью, но в то же оставить и возможность выделять/освобождать память вручную. 2 кучи — одна управляемая a la C#-Java, вторая — неуправляемая a la C++. И были бы и волки сыты и овцы целы. Выбирай, что тебе больше нравится и что больше соотвествует твоей задаче. А может быть, даже и в рамках одной задачи выбирать и то и другое для разных объектов.
Кстати, то же относится к деструктированию объектов. Почему бы не сделать так, чтобы программист мог либо поручить это GC, либо сказать — делай детерминированно сейчас ?
Никаких принципиальных причин, почему это невозможно, я не вижу (если кто видит — скажите). Конечно, в нынешние языки и системы это не лезет. Может, пора новый язык/систему создать с такими возможностями.
Здравствуйте, GlebZ, Вы писали:
GZ>Было много мелких объектов, алгоритм должен был быть очень быстрым. При выделении памяти — стандартный malloc проходил по всей цепочке пытаясь найти место, в результате проседала производительность. Пришлось переопределять new, и делать свой менеджер памяти.
Если алгоритм создаёт много мелких структур и по окончании алгоритма эти структуры становятся не нужны, то лучше использовать не heap (malloc/free или глобальные new/delete), а арену — это такой распределитель памяти вроде stack-а. Вообще, мимолётные временные структуры лучше размещать в арене. Тогда и фрагментация heap-а меньше будет.
GZ>Примерно такая-же ситуация была с VirtualAlloc(работает по тому же принципу).
Переопределить VirtualAlloc не получится .
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, remark, Вы писали:
PD><все skipped после чтения данного сообщения и ответов>
PD>У меня на все это одна мысль возникла. А почему бы авторам некоей системы программирования не совместить GC и не-GC в одной коробке ? То есть ввести в систему GC и его управление памятью, но в то же оставить и возможность выделять/освобождать память вручную. 2 кучи — одна управляемая a la C#-Java, вторая — неуправляемая a la C++. И были бы и волки сыты и овцы целы. Выбирай, что тебе больше нравится и что больше соотвествует твоей задаче. А может быть, даже и в рамках одной задачи выбирать и то и другое для разных объектов.
Ну вот вопрос с ходу. Как отслеживать ссылки из не-GC пула в GC пул?
PD>Кстати, то же относится к деструктированию объектов. Почему бы не сделать так, чтобы программист мог либо поручить это GC, либо сказать — делай детерминированно сейчас ?
А смысл? Проще ввести счётчик ссылок и удалять объект сразу как только у него счётчик упадёт до нуля. GC после этого остаётся только для случаев циклической зависимости, и то — программист может помочь этому разорвав циклы в нужных местах.
Так работает, кстати, python — на долю GC остаются только сложные циклические конструкции.
PD>Никаких принципиальных причин, почему это невозможно, я не вижу (если кто видит — скажите). Конечно, в нынешние языки и системы это не лезет. Может, пора новый язык/систему создать с такими возможностями. :-)
Здравствуйте, Pavel Dvorkin, Вы писали: PD>У меня на все это одна мысль возникла. А почему бы авторам некоей системы программирования не совместить GC и не-GC в одной коробке ? То есть ввести в систему GC и его управление памятью, но в то же оставить и возможность выделять/освобождать память вручную. 2 кучи — одна управляемая a la C#-Java, вторая — неуправляемая a la C++. И были бы и волки сыты и овцы целы. Выбирай, что тебе больше нравится и что больше соотвествует твоей задаче. А может быть, даже и в рамках одной задачи выбирать и то и другое для разных объектов.
Совершенно непонятно, как должна себя вести такая комбинация. Что делать GC, если на управляемый им объект есть ссылки из неуправляемой им кучи? Как ему вообще понять, есть ли эти ссылки?
PD>Кстати, то же относится к деструктированию объектов. Почему бы не сделать так, чтобы программист мог либо поручить это GC, либо сказать — делай детерминированно сейчас ?
И какую семантику это будет иметь? Ну то есть вот допустим есть объект в управляемой куче, и мы говорим "умри!". Использовать место, ранее занимаемое этим объектом, до компактификации кучи всё равно нельзя. Точнее, неоправданно дорого. Делать упаковку сразу — еще дороже. Чем это поможет GC? Если речь не об освобождении памяти (которое GC и так неплохо проводит), то разрушение сводится к вызову определенного метода, после которого объект считается мертвым. В нынешних языках и системах такой метод называется Dispose() и для удобства объявлен в интерфейсе IDisposable.
PD>Никаких принципиальных причин, почему это невозможно, я не вижу (если кто видит — скажите).
Как только ты придумаешь ответы на эти принципиальные вопросы, отличающиеся от того, что есть сейчас, можно приниматься создавать новый язык. PD>Конечно, в нынешние языки и системы это не лезет. Может, пора новый язык/систему создать с такими возможностями.
В одной коробке совместить коня и трепетную лань не получается. Получается развести их по разным коробкам, что можно наблюдать невооруженным взглядом в нынешних языках и системах в полный рост.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Совершенно непонятно, как должна себя вести такая комбинация. Что делать GC, если на управляемый им объект есть ссылки из неуправляемой им кучи? Как ему вообще понять, есть ли эти ссылки?
Из неуправляемой кучи ссылок на управляемые объекты и обратно быть не должно. Не держишь же ты в С++ куче ссылки на автоматические объекты в стеке
Я просто предлагаю разделить эти два множества без пересечения. Если же оно все же потребуется, то идти по пути, аналогичному boxing-unboxing.
PD>>Кстати, то же относится к деструктированию объектов. Почему бы не сделать так, чтобы программист мог либо поручить это GC, либо сказать — делай детерминированно сейчас ? S>И какую семантику это будет иметь? Ну то есть вот допустим есть объект в управляемой куче, и мы говорим "умри!". Использовать место, ранее занимаемое этим объектом, до компактификации кучи всё равно нельзя. Точнее, неоправданно дорого. Делать упаковку сразу — еще дороже. Чем это поможет GC? Если речь не об освобождении памяти (которое GC и так неплохо проводит), то разрушение сводится к вызову определенного метода, после которого объект считается мертвым. В нынешних языках и системах такой метод называется Dispose() и для удобства объявлен в интерфейсе IDisposable.
С этим соглашусь.
S>В одной коробке совместить коня и трепетную лань не получается.
Почему ? Совместили же в C# кучу и стек. Я не вижу, почему стек с GC может в одной коробке уживаться, а неуправляемая куча нет. В конце концов стек от неуправляемой кучи отличается только механизмом выделения/освобожденяи памяти, если уж на то пошло
PD>Почему ? Совместили же в C# кучу и стек. Я не вижу, почему стек с GC может в одной коробке уживаться, а неуправляемая куча нет. В конце концов стек от неуправляемой кучи отличается только механизмом выделения/освобожденяи памяти, если уж на то пошло
Вдогонку. А кстати, почему в C# жестко привязали тип объектов (object или value) к способу размещения (куча или стек). Почему нельзя value разместить в куче или object в стеке ? Это принципиально или просто особенность реализации ?
Здравствуйте, Pavel Dvorkin, Вы писали: PD>Из неуправляемой кучи ссылок на управляемые объекты и обратно быть не должно. Не держишь же ты в С++ куче ссылки на автоматические объекты в стеке PD>Я просто предлагаю разделить эти два множества без пересечения.
Такое уже есть. И давно. Только получается, что это не одна коробка, а две коробки.
PD>Почему ? Совместили же в C# кучу и стек. Я не вижу, почему стек с GC может в одной коробке уживаться, а неуправляемая куча нет.
Ну так посмотри повнимательнее. С GC кстати уживается вовсе не любой стек, а только очень специальный. Обрати внимание, что в дотнете в стеке не могут жить объекты ссылочного типа. PD>В конце концов стек от неуправляемой кучи отличается только механизмом выделения/освобожденяи памяти, если уж на то пошло
Cтек еще много чем отличается. В частности, для того, чтобы стек был безопасным, необходимо запрещать возврат указателей на элементы стека. В управляемых языках так и сделано, а в неуправляемых всё плохо. В куче гарантировать отсутствие циклов невозможно.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>У меня на все это одна мысль возникла. А почему бы авторам некоей системы программирования не совместить GC и не-GC в одной коробке ? То есть ввести в систему GC и его управление памятью, но в то же оставить и возможность выделять/освобождать память вручную. 2 кучи — одна управляемая a la C#-Java, вторая — неуправляемая a la C++. И были бы и волки сыты и овцы целы. Выбирай, что тебе больше нравится и что больше соотвествует твоей задаче. А может быть, даже и в рамках одной задачи выбирать и то и другое для разных объектов.
Такие попытки были. В Modula-3 два типа указателей traced и untraced и, соответственно две кучи.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Кстати, то же относится к деструктированию объектов. Почему бы не сделать так, чтобы программист мог либо поручить это GC, либо сказать — делай детерминированно сейчас ?
Снова изобретаем велосипед?
В управляемых платформах уже есть инструмент детерминирования финализации объектов: кроме жестких ссылок, есть гибкие (WeakReference<T>), легкие (SoftReference<T>) и фантомные (PhantomReference<T>) ссылки — что в Java, что в .NET.
PD>Никаких принципиальных причин, почему это невозможно, я не вижу (если кто видит — скажите). Конечно, в нынешние языки и системы это не лезет. Может, пора новый язык/систему создать с такими возможностями.
И что ж это интересно рукам покоя не дает?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>У меня на все это одна мысль возникла. А почему бы авторам некоей системы программирования не совместить GC и не-GC в одной коробке ? То есть ввести в систему GC и его управление памятью, но в то же оставить и возможность выделять/освобождать память вручную. 2 кучи — одна управляемая a la C#-Java, вторая — неуправляемая a la C++. И были бы и волки сыты и овцы целы. Выбирай, что тебе больше нравится и что больше соотвествует твоей задаче. А может быть, даже и в рамках одной задачи выбирать и то и другое для разных объектов.
В D http://www.digitalmars.com/d/index.html именно так.
PD>Кстати, то же относится к деструктированию объектов. Почему бы не сделать так, чтобы программист мог либо поручить это GC, либо сказать — делай детерминированно сейчас ?
В D есть и RAII и GC и полное ручное управление (переопределяймы new)
PD>Никаких принципиальных причин, почему это невозможно, я не вижу (если кто видит — скажите). Конечно, в нынешние языки и системы это не лезет. Может, пора новый язык/систему создать с такими возможностями.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Pavel Dvorkin, Вы писали: S>Во-первых, value в куче разместить можно. RTFM "Boxing".
Спасибо, а то я не слышал до сих пор об этом. Только это уже не совсем value ИМХО
S>Во-вторых, ссылочный тип в стеке разместить нельзя по принципиальным соображениям: ссылка на такой объект может пережить разрушение фрейма стека и окажется повисшей. А GC собственно придуман для гарантии ссылочной целостности.
Неубедительно. Я не говорю о C# и .Net, но можно представить себе среду, в которой для ссылок на объекты в стеке при разрушении фрейма стека автоматически вызывается "деструктор". Ее кстати и придумывать не надо — C++ unmanaged.
S>Обратное также верно: если ни одна ссылка на объект не может пережить разрушения соответствующего фрейма стека, то объект таки можно разместить в стеке. В новой джаве это реализовано; RTFM "Escape Analysis".
Вот с этим я не знаком. Судя по всему, это аналог того же самого, что и в C++.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Pavel Dvorkin, Вы писали: PD>>Почему ? Совместили же в C# кучу и стек. Я не вижу, почему стек с GC может в одной коробке уживаться, а неуправляемая куча нет. S>Ну так посмотри повнимательнее. С GC кстати уживается вовсе не любой стек, а только очень специальный. Обрати внимание, что в дотнете в стеке не могут жить объекты ссылочного типа.
А нельзя ли объяснить, что такое специальный стек — кроме того, что ты сказал выше, в нем что-то еще особеннное есть ?
PD>>В конце концов стек от неуправляемой кучи отличается только механизмом выделения/освобожденяи памяти, если уж на то пошло S>Cтек еще много чем отличается. В частности, для того, чтобы стек был безопасным, необходимо запрещать возврат указателей на элементы стека.
Равно как и в куче решительно не рекомендуется возвращать указатели на удаленные уже объекты
>В управляемых языках так и сделано, а в неуправляемых всё плохо.
А что тут плохого ?
int* f ()
{
int x;
return &x;
}
warning C4172: returning address of local variable or temporary
Ладно, участие в этой дискуссии прекращаю. Твои аргументы серьезны, но не окончательны. Тем более, что ряд участников этого фрагмента дискуссии привели примеры, где это уже есть. Так что будущее нас рассудит
Здравствуйте, rsn81, Вы писали:
R>В управляемых платформах уже есть инструмент детерминирования финализации объектов: кроме жестких ссылок, есть гибкие (WeakReference<T>), легкие (SoftReference<T>) и фантомные (PhantomReference<T>) ссылки — что в Java, что в .NET.
Всё перечисленное, это как раз недетерменированно.
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, remark, Вы писали:
R>>Здесь можно прочитать более подробно. Кратко суть такая: в C# при использовании асинхронных сокетов (IOCP) в сервере заканчивалось 3GB памяти (летели OutOfMemoryException), хотя "полезных" данных в памяти было примерно 200MB. C>В Java для асинхронного и memory-mapped IO используются unmanaged-буфферы, которые располагаются отдельно от основной кучи. Пиннинг делается только для критичных по скорости кусков нативного кода.
Т.е. получается, что если у меня данные уже лежат в каком-то буфере, то, что бы отправить их в сеть, я обязан их всё равно скопировать в этот специальный буфер (не или фреймворк это сделает, неважно)? Но это же убивает идею на корню...
R>>Многие по началу считают, что при наличии GC этих проблем просто нет. К сожалению это не так. GC обеспечивает только базовую потокобезопасность для ссылок (можно захватывать новые ссылки на объект, только если у тебя уже есть хотя бы одна), но не обеспечивает строгой потокобезопасности для ссылок (возможность захватывать новые ссылки на объект, если у тебя ещё нет ни одной). Т.о. если необходима строгая потокобезопасность, то — мьютекс + счётчик ссылок... Что-то мне это напоминает... R>>Один из примеров можно поглядеть здесь C>В данном случае мьютекс+счетчик — плохое решение. Дело в том, что работать с формой можно безопасно только из одного потока. Нужно было замаршалить вызов в GUI-поток, тогда никаких гонок бы не было.
Дело не в форме и таймере, это может быть с любыми объектами
R>>Какие мысли? C>Примеры надо покрасивее придумать
А я не придумывал
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, remark, Вы писали:
R>>Это абсолютно не бага. Это архитектурная несовместимость GC и асинхронного высокопроизводительного zero-copy ввода-вывода. WH>Это исключительно из-за того что ОС не правильной системы. WH>Если бы ОС была правильной то никакой несовместимости бы небыло... оно бы еще и быстрее чем на классических ОС работало...
Ты ещё скажи, что они неправильное соглашение об именовании идентификаторов использовали, поэтому всё плохо. А вот если бы правильно идентификаторы называли...
Здравствуйте, WolfHound, Вы писали:
R>>Это абсолютно не бага. Это архитектурная несовместимость GC и асинхронного высокопроизводительного zero-copy ввода-вывода. WH>Это исключительно из-за того что ОС не правильной системы. WH>Если бы ОС была правильной то никакой несовместимости бы небыло... оно бы еще и быстрее чем на классических ОС работало...
Благородный дон предлагает нам всем пересесть на AS/400?
Здравствуйте, remark, Вы писали:
C>>В Java для асинхронного и memory-mapped IO используются unmanaged-буфферы, которые располагаются отдельно от основной кучи. Пиннинг делается только для критичных по скорости кусков нативного кода. R>Т.е. получается, что если у меня данные уже лежат в каком-то буфере, то, что бы отправить их в сеть, я обязан их всё равно скопировать в этот специальный буфер (не или фреймворк это сделает, неважно)? Но это же убивает идею на корню...
Если данные уже лежат в NIO-буффере, то просто отдаешь его асинхронному IO. Если же они у тебя в обычном массиве — придется формировать буффер.
R>>>Один из примеров можно поглядеть здесь C>>В данном случае мьютекс+счетчик — плохое решение. Дело в том, что работать с формой можно безопасно только из одного потока. Нужно было замаршалить вызов в GUI-поток, тогда никаких гонок бы не было. R>Дело не в форме и таймере, это может быть с любыми объектами
Так тут простейшие гонки. Просто тупо предусмотреть два логических состояния объекта и тупо игнорировать сообщения таймера в неправильном.
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, remark, Вы писали:
C>>>В Java для асинхронного и memory-mapped IO используются unmanaged-буфферы, которые располагаются отдельно от основной кучи. Пиннинг делается только для критичных по скорости кусков нативного кода. R>>Т.е. получается, что если у меня данные уже лежат в каком-то буфере, то, что бы отправить их в сеть, я обязан их всё равно скопировать в этот специальный буфер (не или фреймворк это сделает, неважно)? Но это же убивает идею на корню... C>Если данные уже лежат в NIO-буффере, то просто отдаешь его асинхронному IO. Если же они у тебя в обычном массиве — придется формировать буффер.
Шило на мыло...
R>>>>Один из примеров можно поглядеть здесь C>>>В данном случае мьютекс+счетчик — плохое решение. Дело в том, что работать с формой можно безопасно только из одного потока. Нужно было замаршалить вызов в GUI-поток, тогда никаких гонок бы не было. R>>Дело не в форме и таймере, это может быть с любыми объектами C>Так тут простейшие гонки. Просто тупо предусмотреть два логических состояния объекта и тупо игнорировать сообщения таймера в неправильном.
Да, простейшие гонки. Но многие изначально наивно считают, что GC решает такие проблемы.
Два состояния — хорошо. А если второе состояние — это объект удалён? Надо делать либо отдельный прокси, либо выносить этот флаг куда-то ещё...
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Всё перечисленное, это как раз недетерменированно.
Детерминировано на том уровне, на котором это в принципе возможно в среде с GC.
Здравствуйте, Pavel Dvorkin, Вы писали: PD>А нельзя ли объяснить, что такое специальный стек — кроме того, что ты сказал выше, в нем что-то еще особеннное есть ?
Да, в частности нельзя взять ссылку на стековый объект. Точнее, нельзя вернуть ссылку на стековый объект вверх; вниз — можно. PD>>>В конце концов стек от неуправляемой кучи отличается только механизмом выделения/освобожденяи памяти, если уж на то пошло S>>Cтек еще много чем отличается. В частности, для того, чтобы стек был безопасным, необходимо запрещать возврат указателей на элементы стека. PD>Равно как и в куче решительно не рекомендуется возвращать указатели на удаленные уже объекты
В GC-куче понятие "указатели на удаленный объект" является оксюмороном.
PD>А что тут плохого ?
PD>
PD>int* f ()
PD>{
PD> int x;
PD> return &x;
PD>}
PD>
PD>warning C4172: returning address of local variable or temporary PD>VS 2005, SP1
Это легко обмануть:
int* f ()
{
int x;
return crashHelper(&x);
}
int* crashHelper(int* pX)
{
return pX;
}
Силы темная сторона давно над C++ возобладала.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>В GC-куче понятие "указатели на удаленный объект" является оксюмороном.
Вот именно про это я и говорил в первом посте
Многие считают, что среда с GC предоставляет многопоточную безопасность в сильном смысле (захват объекта, если ещё нет ссылки на него). GC этого *не* предоставляет. Он предоставляет только *базовую* многопоточную безопасность.
Читаем ещё раз здесь
И думаем над исключением 'Disposed object cannot be accessed'
Здравствуйте, rsn81, Вы писали:
ANS>>Всё перечисленное, это как раз недетерменированно. R>Детерминировано на том уровне, на котором это в принципе возможно в среде с GC.
Хе-хе. Звучит как речь политика Но суть то, не меняется.
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Хе-хе. Звучит как речь политика Но суть то, не меняется.
А пока и не было веских аргументов, что необходима позарез большая степень детерминирования в сфере программирования на управляемых средах.
Здравствуйте, anton_t, Вы писали:
_>Здравствуйте, remark, Вы писали:
R>>Чем не "указатель на удаленный объект"? За исключением терминологии и деталей? R>>Происходит нарушение защиты памяти, расстрел памяти или исключение не суть важно.
_>Дьявол в мелочах. В одном случае получаем аборт приложения в другом ловим исключение, обрабатываем его, логируем и при завершении, по крайней мере, пытаемся вернуть окружающую среду "как было".
Это тут, по-моему, вообще не существенно. Под Win32 это делается аналогично и при нарушении защиты памяти.
Здравствуйте, remark, Вы писали:
R>Данный список не в коей мере не претендует на полноту или ещё на что-либо. Просто набор моментов, которые показались мне интересными.
Я вообще никакой философии не предполагал...
Просто описал ряд конкретных моментов имеющих место быть. Вообще хотел написать (да забыл) — может кто ещё интересных примеров может привести? Мне кажется, должны быть. Я не сказать что бы годами собирал этот список.
R>
E>>Так что, если вспомнить закон потребления пива 20/80, то GC является отличным инструментом в 80% случаев. Зато в оставшихся 20% с ним придется бороться.
E>>Явное же управление памятью наоборот, вызывает лишние затраты в 80% случаев, зато в 20% это именно то, что нужно.
R>Да. Если ты пишешь только 80%. Если же ты пишешь и оставшиеся 20%, и соотв. у тебя есть решения для этих 20%, то не вижу смысла не применять их в других 80%. Точнее так — я не вижу больше проблемы.
Проблемы, возможно, нет научной. А производственная проблема есть — "лишние затраты", овчинка выделки не стоит. GC ее решает.
Здравствуйте, Klapaucius, Вы писали:
FR>>В D есть и RAII и GC и полное ручное управление (переопределяймы new)
K>За это приходится расплачиваться. GC в D консервативный, а не точный.
AFAIK, это деталь текущей реализации, а не принципиальная особенность языка. Разработчики Tango используют собственную версию GC, которая несколько быстрее штатной. И сама архитектура Tango подразумевает возможность смены GC. Тут вопрос упирается в то, что в D community пока никто лучшего GC не написал.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, mselez, Вы писали:
M>Здравствуйте, remark, Вы писали:
E>>>Так что, если вспомнить закон потребления пива 20/80, то GC является отличным инструментом в 80% случаев. Зато в оставшихся 20% с ним придется бороться.
E>>>Явное же управление памятью наоборот, вызывает лишние затраты в 80% случаев, зато в 20% это именно то, что нужно.
R>>Да. Если ты пишешь только 80%. Если же ты пишешь и оставшиеся 20%, и соотв. у тебя есть решения для этих 20%, то не вижу смысла не применять их в других 80%. Точнее так — я не вижу больше проблемы.
M>Проблемы, возможно, нет научной. А производственная проблема есть — "лишние затраты", овчинка выделки не стоит. GC ее решает.
Какие тут лишние затраты? Тут нет никаких лишних затрат.
Здравствуйте, eao197, Вы писали:
FR>>>В D есть и RAII и GC и полное ручное управление (переопределяймы new) K>>За это приходится расплачиваться. GC в D консервативный, а не точный. E>AFAIK, это деталь текущей реализации, а не принципиальная особенность языка. Разработчики Tango используют собственную версию GC, которая несколько быстрее штатной. И сама архитектура Tango подразумевает возможность смены GC. Тут вопрос упирается в то, что в D community пока никто лучшего GC не написал.
А на сколько я знаю, возможность использования точного GC предъявляет требования к дизайну языка. Увы — жизнь это не только музыка и цветы.
... << RSDN@Home 1.2.0 alpha rev. 730>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, remark, Вы писали:
PD><все skipped после чтения данного сообщения и ответов>
PD>У меня на все это одна мысль возникла. А почему бы авторам некоей системы программирования не совместить GC и не-GC в одной коробке ? То есть ввести в систему GC и его управление памятью, но в то же оставить и возможность выделять/освобождать память вручную. 2 кучи — одна управляемая a la C#-Java, вторая — неуправляемая a la C++. И были бы и волки сыты и овцы целы. Выбирай, что тебе больше нравится и что больше соотвествует твоей задаче. А может быть, даже и в рамках одной задачи выбирать и то и другое для разных PD> объектов.
..
Другая важная часть RTSJ—это введение новых областей памяти, отличных от обычной кучи (heap), используемой в Java. Работа с этими областями памяти осуществляется с помощью класса ScopedMemory. Объекты ScopedMemory должны создаваться непосредственно программистом, например:
// создать область памяти размером 1MB (LTMemory — стандартный подкласс ScopedMemory)
ScopedMemory scopedMemory = new LTMemory(1024 * 1024);
Создаваемая таким образом память не управляется сборщиком мусора. Очищаются эти области памяти в тот момент, когда не остаётся работающих в них потоков. Рамки использования памяти задаются синтаксически: поток использует ScopedMemory, пока он выполняет метод ScopedMemory.enter. Также надо отметить, что области ScopedMemory доступны только для потоков реального времени.
..
Здравствуйте, Klapaucius, Вы писали:
FR>>>>В D есть и RAII и GC и полное ручное управление (переопределяймы new) K>>>За это приходится расплачиваться. GC в D консервативный, а не точный. E>>AFAIK, это деталь текущей реализации, а не принципиальная особенность языка. Разработчики Tango используют собственную версию GC, которая несколько быстрее штатной. И сама архитектура Tango подразумевает возможность смены GC. Тут вопрос упирается в то, что в D community пока никто лучшего GC не написал.
K>А на сколько я знаю, возможность использования точного GC предъявляет требования к дизайну языка.
Ирония в том, что для D консервативный GC опаснее, чем точный. Поскольку консервативный GC не в состоянии отличить значения float, полученные в результате каких-нибудь расчетов, от указателей. И вполне может принять массив float-ов за массив указателей. Что и просходило вскоре после выпуска D1.0 и что обсуждалось в digitalmars.D. Поэтому уже в D1.001 GC был изменен так, чтобы использовать информацию о типах.
K>Увы — жизнь это не только музыка и цветы.
Да, я здесь громче всех утверждаю, что в жизни есть только музыка и цветы. Спасибо, что напомнили.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, remark, Вы писали:
R>>Неожиданное исчерпание свободной памяти. R>>Возникает при использовании пиннинга памяти. Не обязательно явном. Например при использовании асинхронного ввода-вывода ран-тайм скорее всего сам будет делать пиннинг памяти. В CLI такая возможность так же присутствует в явном виде, в Java — не знаю. Суть пиннинга — запрещение перемещения объекта в памяти. Это может препятствовать "уплотнению" используемой памяти во время сборки мусора, таким образом используемая память будет сильно фрагментирована и "кпд" использования памяти резко снижается. R>>Здесь можно прочитать более подробно. Кратко суть такая: в C# при использовании асинхронных сокетов (IOCP) в сервере заканчивалось 3GB памяти (летели OutOfMemoryException), хотя "полезных" данных в памяти было примерно 200MB.
VD>Проблема была вызвана кривым решением в CLR. На сегодня она исправлена (если не ошибаюсь во Фрэймворке 2.0 ее уже нет).
А как они решили? Как в Java?
VD>Ввывод — это не проблема GC в общем, а проблема конкретной реализации.
Это всё проблемы реализаций. Точнее так — это проблемы, с которыми можно сталкнуться в реальности, если используешь GC. Возможно я немного неточно назвал тему...
R>>Постепенная и периодическая деградация производительности и рост используемой памяти под нагрузкой. R>>Подробности здесь. Кратко: в Java при использовании WeakHashMap и включении Concurrent GC вместо штатного начали проявляться упомянутые эффекты. Оказалось, что под нагрузкой большую часть элементов WeakHashMap постоянно "трогают", хотя реально не используют. Это "троганье" предотвращало удаление каких-либо объектов из WeakHashMap вообще. Соответственно он неограниченно рос, пока весь сервер не затыкался на некоторое время. Во время затыкания элементы WeakHashMap никто не "трогал", и соотв. они все удалялись. Все становится хорошо. А потом по новой. Со штатным GC такой эффект не наблюдается.
VD>Опять же... Сам говришь, что проблема проявляется только с кокретной реализацией GC. Значит и это проблема реализации.
Да.
R>>Ну более-менее стандартная проблема с временем жизни и владением объектами. R>>Многие по началу считают, что при наличии GC этих проблем просто нет. К сожалению это не так. GC обеспечивает только базовую потокобезопасность для ссылок (можно захватывать новые ссылки на объект, только если у тебя уже есть хотя бы одна), но не обеспечивает строгой потокобезопасности для ссылок (возможность захватывать новые ссылки на объект, если у тебя ещё нет ни одной). Т.о. если необходима строгая потокобезопасность, то — мьютекс + счётчик ссылок... Что-то мне это напоминает... R>>Один из примеров можно поглядеть здесь
VD>Ни Ява, ни дотнет не содержат серьзных средств упрощающих многопоточную разработку. GC тут просто не причем.
GC тут косвенно при чём. Т.к. такие посты и заметки в блоках встречаются с некоторой регулярностью.
VD>Более того есть системы с GC которые как раз радикально упрощают разработку многопточных систем (Эрлэнг, Сингулярити и т.п.).
Они могли бы так же быть построены и на основе синхронного удаления объектов, используя подсчёт ссылок.
R>>Какие мысли?
VD>Мысль одна. Не следует обсуждать слухи. А уж если полез обсуждать, то разберись в проблематике.
Это не слухи. Это — факты. Факты про конкрутные реализации — не спорю.
VD>GC не иделное решене. У него есть проблемы. Одна из главных проблем — это увеличение потребности в памяти. GC работает эффективно только при наличии запаса свободной памяти. Он как бы меняет лишнюю память на автоматическое упрваление ею.
VD>Кроме того GC сам по себе не предоставляет средств управления другими ресурсами и выявления проблем с неосвобождением памяти (складыванием ее в кучу). Однако эти проблемы могут быть решены отладчиками, языками программирования и инструментальными средствами.
VD>Ну, а описанные здесь "проблемы" не более чем громкие охания.
Да, это — действительно громкие охания... человека который провёл месяц в отладчике
Здравствуйте, remark, Вы писали:
R>А как они решили? Как в Java?
Боюсь наврать, так как давно изучал вопрос, но примерно было так.
В ЖЦ 1.х если находились заблокированные объекты, то сжатие за них не проводилось. Куча как бы застывала последнем запиненом объекте. Это приводило к тому, что куча со временем становилась фрагментированной. В итоге могла свободно кончиться память. В номом фрэймворке это как-то обошли. Как точно не помню. Проще поискать описание.
VD>>Ввывод — это не проблема GC в общем, а проблема конкретной реализации.
R>Это всё проблемы реализаций.
Ага.
R>Точнее так — это проблемы, с которыми можно сталкнуться в реальности, если используешь GC.
Не-ааа.
R> Возможно я немного неточно назвал тему...
Ты бы лучше создал бы тему по поводу недостатков обычных С-хипов. А то вот реализация что используется в Виндовс на редкость кривая и дико тормозит (особенно в многопточном окружении). Тогда бы мы поглядели что за выводы ты сделаешь. Ведь если идти твоим путем, то можно или Виндовс с дермом смешать или все С-хипы.
Если не понятно, то попробую пояснить на базе аналогии. Возьмем, к рпимеру, сотовые телефоны. То что у некоторых из них есть проблемы еще не значит, что все GSM-телефоны ущербны. Ну, мало ли там один из видов в одной из версий плохой прием имеет? Что с того? Вот то же самое с ЖЦ. Нельзя ставить ярмо на сам подход если в отдельных версях были некоторые проблемы.
VD>>Ни Ява, ни дотнет не содержат серьзных средств упрощающих многопоточную разработку. GC тут просто не причем.
R>GC тут косвенно при чём. Т.к. такие посты и заметки в блоках встречаются с некоторой регулярностью.
Тебе не кажется, что ты сам себе противоречишь?
VD>>Более того есть системы с GC которые как раз радикально упрощают разработку многопточных систем (Эрлэнг, Сингулярити и т.п.).
R>Они могли бы так же быть построены и на основе синхронного удаления объектов, используя подсчёт ссылок.
А это соврешенно не важно. Важно, что эти факты опровергают твои предположения о том, что ЖЦ мол как-то плохо влияет на многопоточне вычисления.
Подитоживая могу с уверенностью сказать, что твои выводы — это демонстрация некорректной логики. А это, в своею очередь, может быть или от плохого владения ею, или банальным не честным приемом дисскусси.
R>>>Какие мысли?
VD>>Мысль одна. Не следует обсуждать слухи. А уж если полез обсуждать, то разберись в проблематике.
R>Это не слухи. Это — факты. Факты про конкрутные реализации — не спорю.
VD>>GC не иделное решене. У него есть проблемы. Одна из главных проблем — это увеличение потребности в памяти. GC работает эффективно только при наличии запаса свободной памяти. Он как бы меняет лишнюю память на автоматическое упрваление ею.
VD>>Кроме того GC сам по себе не предоставляет средств управления другими ресурсами и выявления проблем с неосвобождением памяти (складыванием ее в кучу). Однако эти проблемы могут быть решены отладчиками, языками программирования и инструментальными средствами.
VD>>Ну, а описанные здесь "проблемы" не более чем громкие охания.
R>Да, это — действительно громкие охания... человека который провёл месяц в отладчике
R> R>
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Ты бы лучше создал бы тему по поводу недостатков обычных С-хипов. А то вот реализация что используется в Виндовс на редкость кривая и дико тормозит (особенно в многопточном окружении). Тогда бы мы поглядели что за выводы ты сделаешь. Ведь если идти твоим путем, то можно или Виндовс с дермом смешать или все С-хипы.
VD>Если не понятно, то попробую пояснить на базе аналогии. Возьмем, к рпимеру, сотовые телефоны. То что у некоторых из них есть проблемы еще не значит, что все GSM-телефоны ущербны. Ну, мало ли там один из видов в одной из версий плохой прием имеет? Что с того? Вот то же самое с ЖЦ. Нельзя ставить ярмо на сам подход если в отдельных версях были некоторые проблемы.
Влад, я ничего не говорил про GC в целом. Ты сам придумываешь какие-то аргументы за меня, а потом сам на них отвечаешь. Я имел в виду только то, что написал. Ни больше, и не меньше. Конкретные люди сталкнулись с конкретными проблемами. Ссылки я дал. Если там что-то некорректно написано, то обращайся к тем людям.
На всякий случай, про goto я тоже ничего не говорил
Здравствуйте, eao197, Вы писали:
E>А в случае с GC объект result содержал бы валидную ссылку. И оказалось бы, что switch_to_delayed_filter возвращает совсем не тот фильтр, который находится в m_actual. И ничего бы не падало. Просто работало бы не так как нужно. И еще не понятно, когда бы все всплыло, ведь в тестах у меня все клиенты использовали одинаковые фильтры
Прочитай в MSDN про Dictionary.System.Collections.IDictionary.Add раздел Exceptions...
ЗЫ А вобще логика офигенная: ГЦ плохо по тому что у меня руки кривые.
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
[]
E>Суть вот в чем: есть два map-а, ключами в которых являются идентификаторы клиентов, а значениями -- ссылки на соответствующие этим клиентам объекты (в данном случае фильтры). В одном map-е хранятся фильтры, которые еще не прошли подтверждение, а во втором -- уже подтвержденые. И есть операция switch_to_delayed_filter, которая перемещает фильтр из одного map-а в другой, возвращая указатель на фильтр: E>
E>filter_t *
E>channel_filters_t::switch_to_delayed_filter(
E> const client_id_t & id )
E> {
E> // Ищем отложенный фильтр в map-е еще не подтвержденных.
E> filter_map_t::iterator it = m_delayed.find( id );
E> if( it != m_delayed.end() )
E> {
E> // Перемещаем из одного map-а в другой.
E> filter_t * result = it->second.get();
E> m_actual.insert( *it );
E> m_delayed.erase( it );
E> return result;
E> }
E> else
E> // Ну нет такого фильра, пускай наверху разбираются.
E> return 0;
E> }
E>
[]
как я понял, фильтр в delayed != фильтру в actual? Прости, но кто так делает (см. выд.)? Ты ССЗБ
E>> // Перемещаем из одного map-а в другой.
E>> filter_t * result = it->second.get();
E>>
КЛ>как я понял, фильтр в delayed != фильтру в actual? Прости, но кто так делает (см. выд.)? Ты ССЗБ
А что такого? В map-е значением лежит shared_ptr, его метод get() возвращает голый указатель, который мне нужен был для возвращаемого значения. При условии, что это shared_ptr не разрушается при переносе из map-а в map, криминала я не вижу.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, McSeem2, Вы писали:
MS>Нет, логика такая — GC плох потому, что он жрет мозг. И самая главная подлость GC — он делает это так незаметно, что жертва GC, сама того не сознавая, начинает молиться на него, воздавать хвалы и выполнять ритуальные жертвоприношения.
Мы где? В семенарии или на техническом форуме?
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
[]
E>А что такого? В map-е значением лежит shared_ptr, его метод get() возвращает голый указатель, который мне нужен был для возвращаемого значения. При условии, что это shared_ptr не разрушается при переносе из map-а в map, криминала я не вижу.
Вот потому и получил эту проблему, что не видишь. Просто небезопасно это. Я так очень редко делаю.
Обычно так:
filter_tptr filter = filters[ id ];
или
filter_tptr const& filter = filters[ id ];
Здравствуйте, Константин Л., Вы писали:
E>>А что такого? В map-е значением лежит shared_ptr, его метод get() возвращает голый указатель, который мне нужен был для возвращаемого значения. При условии, что это shared_ptr не разрушается при переносе из map-а в map, криминала я не вижу.
КЛ>Вот потому и получил эту проблему, что не видишь. Просто небезопасно это. Я так очень редко делаю. КЛ>Обычно так:
КЛ>
КЛ>filter_tptr filter = filters[ id ];
КЛ>
На неконстантном map-е оператор[] для несуществующего ключа может привести к интересным глюкам -- вставке пустого элемента в map. А если воспользоваться map::find, то уже есть iterator, из которого можно брать все, что нужно.
КЛ>Ну а уж голый поинтер возвращать — нерулез.
Снаружи switch_to_delayed_channel мне нужен был именно указатель, т.к. то, что внутри хранилища фильтров используются shared_ptr -- это детали реализации, которые клиентов хранилища интересовать не должны.
К тому же возвращение shared_ptr в данном случае привело бы к сокрытию проблемы, как и в случае GC.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
[]
E>На неконстантном map-е оператор[] для несуществующего ключа может привести к интересным глюкам -- вставке пустого элемента в map. А если воспользоваться map::find, то уже есть iterator, из которого можно брать все, что нужно.
совершенно верно, это был псевдокод
КЛ>>Ну а уж голый поинтер возвращать — нерулез.
[]
E>К тому же возвращение shared_ptr в данном случае привело бы к сокрытию проблемы, как и в случае GC.
Ну к сокрытию проблемы может привести все, что угодно. Так что, по моему мнению, гц тут не при чем.
Неплохо бы проверять результат map::insert. Да и вообще — обычный bl баг
Здравствуйте, Константин Л., Вы писали:
КЛ>Ну к сокрытию проблемы может привести все, что угодно. Так что, по моему мнению, гц тут не при чем.
КЛ>Неплохо бы проверять результат map::insert.
Может быть, но я так и не научился писать код вида:
if( !m_actual.insert( *it ) )
abort(); /* больше уже все равно ничего не сделать */
КЛ>Да и вообще — обычный bl баг
Мой поинт был в том, что если из-за bl бага в C/C++ оказывается бесхозный указатель, то это приводит к краху программы. А в случае с GC бесхозная ссылка оставить программу работать.
Т.е. GC прощает ошибки там, где явное управление памятью со всей силы бьет по рукам.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Может быть, но я так и не научился писать код вида: E>
E>if( !m_actual.insert( *it ) )
E> abort(); /* больше уже все равно ничего не сделать */
E>
template<typename container_t>
void ensure_insert(container_t& c, typename container_t::const_reference v)
{
if (!c.insert(v).second)
{
assert(false);
throw std::logic_error("element doubling");
// or just abort()
}
}
ensure_insert(m, *it);
Во-первых, вместо просто abort(), желательно вначале сделать assert(false), т.к. ошибка логическая.
Во-вторых, стандартной библиотеке, действительно, не хватает многих удобных функций, типа таких:
Здравствуйте, remark, Вы писали:
R>Влад, я ничего не говорил про GC в целом. Ты сам придумываешь какие-то аргументы за меня, а потом сам на них отвечаешь. Я имел в виду только то, что написал. Ни больше, и не меньше. Конкретные люди сталкнулись с конкретными проблемами. Ссылки я дал. Если там что-то некорректно написано, то обращайся к тем людям.
ОК. Тогда зачем вся эта тема? Ну, какова ее цель? Ведь конкретные люди сталкивались с конкретными проблемами и при работе с кучей С/С++. Почему ты не посвятил свою тему этому?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
R>>Влад, я ничего не говорил про GC в целом. Ты сам придумываешь какие-то аргументы за меня, а потом сам на них отвечаешь. Я имел в виду только то, что написал. Ни больше, и не меньше. Конкретные люди сталкнулись с конкретными проблемами. Ссылки я дал. Если там что-то некорректно написано, то обращайся к тем людям.
VD>ОК. Тогда зачем вся эта тема? Ну, какова ее цель? Ведь конкретные люди сталкивались с конкретными проблемами и при работе с кучей С/С++. Почему ты не посвятил свою тему этому?
А почему я не посвятил свою тему арбузам? Многим бы было интересно.
А почему ты не посвящаешь свои темы организации кэшей современных процессоров? Мне было бы интересно!
Или тут можно постить только по квотам от тебя?
Спасибо.
Вывод как я понял следующий. Там были [не очень] неявные ссылки между объектами, которые заставляли зависать в памяти очень большое дерево объектов.
Здравствуйте, remark, Вы писали: R>Спасибо. R>Вывод как я понял следующий. Там были [не очень] неявные ссылки между объектами, которые заставляли зависать в памяти очень большое дерево объектов.
Я так понял, что проблема близка к знаменитой беде с делегатами в .Net. Позволю себе напомнить, что неаккуратная подписка объекта на событие завешивает его в памяти навсегда.
Прелесть в том, что раз ссылок, кроме делегата, на объект нету, то шансов на отписку ~0.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, remark, Вы писали:
R>А можешь пример привести, как можно неаккуратно подписаться на событие.
Пример можно найти в SVN RSDN@Home двух-трех-летней давности
Обычная штука, к примеру: форма подписывается на уведомления об изменении модели, и при закрытии забывает отписаться. Всё, копец. Закрытые формы копятся и копятся. R>
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, remark, Вы писали:
R>>А можешь пример привести, как можно неаккуратно подписаться на событие. S>Пример можно найти в SVN RSDN@Home двух-трех-летней давности S>Обычная штука, к примеру: форма подписывается на уведомления об изменении модели, и при закрытии забывает отписаться. Всё, копец. Закрытые формы копятся и копятся.
На слабых ссылках нужно было это делать. Было бы помедленнее, но зато не нужно заботиться от отписывании.
Здравствуйте, Sinclair, Вы писали:
R>>Вывод как я понял следующий. Там были [не очень] неявные ссылки между объектами, которые заставляли зависать в памяти очень большое дерево объектов. S>Я так понял, что проблема близка к знаменитой беде с делегатами в .Net.
Не, тут просто баг. Вместо очищения ссылки она запоминается. Даже если бы не было замыкания со ссылками на окружение, то это была бы утечка всё равно. Просто она была бы мизерная и её никто бы не стал искать.
Здравствуйте, alexeiz, Вы писали: A>На слабых ссылках нужно было это делать. Было бы помедленнее, но зато не нужно заботиться от отписывании.
Есть реализации делегатов на слабых ссылках; но встраивать слабость делегатов в платформу, имхо, спорный вариант.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Cyberax, Вы писали: C>Более сильный вариант: встраивать делегаты в платформу — спорный вариант C>(ИМХО).
Я так не думаю. Без поддержки платформы состряпать свои делегаты, мягко говоря, трудно. Вряд ли удастся обеспечить ковариантность, и будут проблемы с быстродействием.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Sinclair wrote: > C>Более сильный вариант: встраивать делегаты в платформу — спорный вариант > C>(ИМХО). > Я так не думаю. Без поддержки платформы состряпать свои делегаты, мягко > говоря, трудно. Вряд ли удастся обеспечить ковариантность, и будут > проблемы с быстродействием.
Вполне можно — достаточно иметь ковариантность для интерфейсов. От языка
разве что синтаксический сахар можно было бы добавить.
Здравствуйте, Sinclair, Вы писали:
S>Пример можно найти в SVN RSDN@Home двух-трех-летней давности S>Обычная штука, к примеру: форма подписывается на уведомления об изменении модели, и при закрытии забывает отписаться. Всё, копец. Закрытые формы копятся и копятся.
Там все было сложнее. Там был синглтон к событиям которого подписывались. Иначе бы подписчики умерли бы вместе с формой.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.