Здравствуйте, Denis2005, Вы писали:
D>Здравствуйте, Left2, Вы писали:
D>>>MS переписал код с "кустарного C" на C, который можно без проблем прогнать через рядовой С++ компилятор. D>>>В частности объявления в стиле K&R были заменены на ANSI-шные.
L>>... Насколько я видел — в call-stack большинство вызываемых функций являются членами классов...
D>Во первых стоит уточнить о каких “80-90% кода XP“ шла речь. D>Ядро, API, базовые библиотеки и сервисы сделаны на C, просто были переработаны и адаптированы на подмножество, которое нормально поддерживается стандартом C++.
D>Далее немалая часть кода переведена с C на C++ почти машинным способом (наглядный пример фрагменты MFC).
D>Имели (C): D>
D>struct HDC;
D>void Proc(HDC hdc, …);
D>
D>Получили (C++): D>
D>class CDC
D>{
D> …
D> void Proc(…)
D>}
D>
D>В принципе разница только в том, что (для MS-компиляторов) указатель на объект/структуру будет передан через регистр (как правило ECX). Назвать это C++ можно с большой натяжкой.
D>Поэтому заявление: “… процентов 80-90 кода на С++”, стоило бы заменить на “процентов 80-90 пародии на C++”.
Ты сделал большой комплимент создателям MFC, сказав, что они сделали свою библиотеку на некоторой пародии на C++. Нет, товарищ, код этой библиотеки является для них высшим образцом применения языка C++. По их мнению, это С++, какой он должен быть. И лучше чем это не бывает. И не надо мне рассказывать, что это был 92-й год, С++ в зачатке, итд итп. Если бы хоть кто-либо понимал, что это пародия на С++, код этой библиотеки бы исправили. Благо возможностей было много.
Вообще, в отношении С++ Майкрософт представляет очень упорный бастион. Новые идей дизайна и программирования на С++ эту компанию обходят стороной. Да какие там новые идеи! Видев огромное количество кода (очень много доступно открыто, например, SSCLI, Windows CE, Platform SDK, Win2K для тех кто успел скачать ), я могу смело сказать, что С++ в Майкрософте остановился на уровне 94 года (т.е. STL'ом там и не пахнет, хорошо хоть шаблоны попадаются изредка). Вот я недавно завладел ARM'ом, так это 90-й год. Если придерживаться хотя бы советов из этой книги, то можно гораздо лучше код писать.
Здравствуйте, alexeiz, Вы писали:
A> ... И не надо мне рассказывать, что это был 92-й год, С++ в зачатке, итд итп.
C++ в зачатке был году этак в 85-м, когда как раз официально вышла версия 1.0.
A> ... в Майкрософте остановился на уровне 94 года (т.е. STL'ом там и не пахнет, хорошо хоть шаблоны попадаются изредка). Вот я недавно завладел ARM'ом, так это 90-й год...
В 94-ом уже был STL, правда его использование на тот момент стояло под большим вопросом, т.к. необходимо было иметь достаточно хорошие оптимизаторы, да и время компиляции для крупных проектов играло не последную роль.
ARM на сколько я знаю написан по 2.0 (которого еще не было), и компиляторы в 1989-1991 его чуток поддерживали.
В частости Borland Turbo C++ 1.0, умел с горем пополам работать с шаблонами, но не имел exception handling и т.д.
Здравствуйте, Denis2005, Вы писали:
D>В частости Borland Turbo C++ 1.0, умел с горем пополам работать с шаблонами, но не имел exception handling и т.д.
Turbo C++ 1.0 вряд ли. Так же, как и Borland C++ 2.0.
Какие-то подвижки начались с появлением Borland C++ 3.0/3.1, но с ними я практически не работал, т.к. довольно быстро появились Borland C++ 4.0, а затем и 4.1. В одном из них была поддержка шаблонов, а во второй добавили поддержку исключений (либо в обратном порядке, уже не помню). Так же они позволяли создавать 32-х битовый код для Windows (Win32s и бетаверсии Win95). Причем в 4.0 были какие-то проблемы с линковкой 32-х битовых приложений в Win16.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Denis2005, Вы писали:
D>>В частости Borland Turbo C++ 1.0, умел с горем пополам работать с шаблонами, но не имел exception handling и т.д.
E>Turbo C++ 1.0 вряд ли. Так же, как и Borland C++ 2.0...
Извиняюсь, в TC++ 1.01 просто было зарезервированно ключевое слово template.
Turbo C++ version 1 was our first compiler that supported the C++ language. The C++ compiler conformed to AT&T's 2.0 specification for the C++ language.
Шаблоны у Борланда в простейшем виде появились только в BC++ 3.0.
Здравствуйте, alexeiz, Вы писали:
A>... я могу смело сказать, что С++ в Майкрософте остановился на уровне 94 года (т.е. STL'ом там и не пахнет, хорошо хоть шаблоны попадаются изредка).
Вот и хорошо что там не пахнет STL-ем. Запаха МФЦ вполне достаточно, а если еще и запах STL... нет это уже перебор.
Здравствуйте, Cyberax, Вы писали:
C>Но не самый быстрый. Знаю коммерческий аллокатор, работающий за O(1) для C>блоков небольшого размера.
Тут дело даже не в том, что теоетически можно написать супер-аллокатор, применив какие-то инновационные супер оптимальные алгоритмы, которые в конечном счете "порвут" ГЦ. Нет, вся соль в том, что в аллокаторах можно учесть специфику конкретного приложения, благодаря которой можно реализовать крайне эффективное управление памятью, с которой не сможет сравниться никакие универсальные ГЦ и кучи. Например, очень часто можно заметить, что 90% некоторых объектов в программе удаляются (то есть становятся ненужными) в той же последовательности, что и создаются. В этом случае можно использовать супер эффективный менеджер памяти, реализованный на основе циклического буффера. Он будет работать, как О(1), причем константа будет чрезвычайно мала (порядка нескольких команд процессора). Пример такой задачи: к нам приходят сообщения, мы их накапливаем в некотором буффере и постепенно обрабатываем. После обработки сообщение нас больше не интересует. Никакой универсальный ГЦ или хип не сравнятся на этой задаче с тривиальным менеджером памяти на циклическом буффере. Вместо циклического буффера можно использовать, например, стек, в случае, если объекты чаще всего удаляются в порядке обратном созданию. Если подобные задачи покажутся слишком редкими и специфическими, то я не соглашусь с этим. Очень во многих задачах не принципиален порядок уничтожения объектов и часто можно весьма безболезненно сделать так, чтобы объекты преимущественно удалялись в удобном нам порядке. Именно тут мне видится наибольшая польза от возможности ручного управления памятью. Этой возможностью мне приходилось в свое время очень успешно пользоваться, благодаря чему производительность увеличивалась на порядки (узким местом был именно хип)
Здравствуйте, prVovik, Вы писали:
V>Пример такой задачи: к нам приходят сообщения, мы их накапливаем в некотором буффере и постепенно обрабатываем. После обработки сообщение нас больше не интересует. Никакой универсальный ГЦ или хип не сравнятся на этой задаче с тривиальным менеджером памяти на циклическом буффере.
Думаю, что GC на подобной задаче покажет себя очень неплохо. Остаётся лишь выяснить стоит ли те несколько процентов повышения производительности того гемороя, который придётся поиметь при разработке подобного аллокатора, вылавливании глюков и переделок в связи с не сразу замеченными косяками в архитектуре.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
V>>Пример такой задачи: к нам приходят сообщения, мы их накапливаем в некотором буффере и постепенно обрабатываем. После обработки сообщение нас больше не интересует. Никакой универсальный ГЦ или хип не сравнятся на этой задаче с тривиальным менеджером памяти на циклическом буффере.
IT>Думаю, что GC на подобной задаче покажет себя очень неплохо. Остаётся лишь выяснить стоит ли те несколько процентов повышения производительности того гемороя, который придётся поиметь при разработке подобного аллокатора, вылавливании глюков и переделок в связи с не сразу замеченными косяками в архитектуре.
Если это менеджер, который не выделяет память динамически, а использует заранее выделенные буффера памяти, то на ряде задач вполне себя оправдает. Например, похожую схему мне доводилось использовать в системе реального времени, где вся память выделялась при старте системы, а затем просто по кругу перемещался маркер текущего буфера. Никакого геморроя с этим моментом не было, наоборот это была одна из самых тривиальных и предсказуемых частей системы
И кстати, об удобстве. Когда-то в исходниках редактора cooled (из Midnight Commander-а) видел такой фокус по динамическому распределению памяти. Во многих функциях требовалось распределить динамически память, сохранить туда какую-нибудь строку и вернуть указатель на эту память куда-то наверх. Чтобы не заморачиваться с владением памяти и ответственностью за ее удаление, в cooled был применен простой хак. Для выделения такой памяти использовалась специальная функция (названия не помню, пусть будет get_temp_mem()), которая внутри себя владела очередью указателей (на обычном векторе). Как только требовалось память, она выделялась и указатель на нее помещался в данную очередь, после чего возвращался из get_temp_mem(). При этом, если в очереди оказывалось N+1 элементов, то самый старый из них просто удалялся из очереди, а его память освобождалось. Все это работало в предположении, что в один момент времени в программе не может жить больше, чем N указателей, возвращенных get_temp_mem().
Хак, конечно, потенциально опасный. Но, т.к. приложение однопоточное и временные указатели нигде на долго не сохранялись, то даже для небольшого N (кажется, 10) использование get_temp_mem() было вполне безопасным. Но важно, что его использование в чистом C коде было удобным, т.к. не нужно было заботиться об освобождении памяти.
Если же эту схему доработать... Например, использовать в get_temp_mem() циклический буфер и освобождать очередной указатель только, если памяти под ним недостаточно, то после некоторого количества обращений к get_temp_mem() окажется, что размеры буферов стабилизировались и новых обращений к alloc/free вообще не будет.
Применительно к C++ подобные трюки можно делать не только на уровне allocator-ов для STL-контейнеров. Но и даже на уровне собственных new/delete для отдельных классов (если объекты этих классов динамически создаются в программе слишком часто).
Ну это так, вспомнилось.
А GC действительно во многих случаях делает жизнь гораздо проще.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, prVovik, Вы писали:
V>Тут дело даже не в том, что теоетически можно написать супер-аллокатор, применив какие-то инновационные супер оптимальные алгоритмы, которые в конечном счете "порвут" ГЦ. Нет, вся соль в том, что в аллокаторах можно учесть специфику конкретного приложения, благодаря которой можно реализовать крайне эффективное управление памятью, с которой не сможет сравниться никакие универсальные ГЦ и кучи.
Хм. Несомненно! Как несомнено то, что потенциально можно написать любую программу на ассемблере и добиться того, что она будет быстрее любой скомпилированной с высокоуровневого языка.
Вот только не некотором объеме оказывается, что затраты на ручную оптимизацию слишком высоки. К тому же оказывается, что для того чтобы осуществить эти оптимизации нужно обладать нехилыми знаниями в довольно тонких вопросах (вроде влияния кэша процессора и т.п.). Ну, и в итоге получается, что в 99.9% случаев GC окажется предпочтительнее.
V> Например, очень часто можно заметить, что 90% некоторых объектов в программе удаляются (то есть становятся ненужными) в той же последовательности, что и создаются. В этом случае можно использовать супер эффективный менеджер памяти, реализованный на основе циклического буффера. Он будет работать, как О(1), причем константа будет чрезвычайно мала (порядка нескольких команд процессора). Пример такой задачи: к нам приходят сообщения, мы их накапливаем в некотором буффере и постепенно обрабатываем. После обработки сообщение нас больше не интересует.
А сообщения одного размера? Ой не верю. А если разных, то твоя идея идет лесом, так как блок маленького размера будет непригоден для следующего сообщения имеющего больший размер.
В то же время ЖЦ основанный на поколениях довольно эффективно разрулит эту ситуацию. Он попросту включится когда нулевое поколение переполнится и сдвинет все живые объекты в первое поколение. Далее сообщения можно будет выделять очень долго. Когда же пройдет несколько таких циклов сдвижек и нулевое поколение станет слишком маленьким, то будет запущена сборка первого поколения в котором к тому времени уже все сообщения умрут.
Что мы имеем в итоге? А имеем довольно быстрое решиние не завязанное на частности вроде той, что блоки должны иметь одинаковый размер.
V> Никакой универсальный ГЦ или хип не сравнятся на этой задаче с тривиальным менеджером памяти на циклическом буффере.
Можно сслочку на то, где ты видел подобные решения в реальной жизни? Сколько таких случаев было?
V> Вместо циклического буффера можно использовать, например, стек, в случае, если объекты чаще всего удаляются в порядке обратном созданию.
В случае если нужен стек, то использовать лучше стек.
И чаще всего тут не катит. Только если объекты живут в стиле LIFO.
Так вот в ЖЦ Явы уже скоро появится такая оптимизация. Если из анализа кода будет выявлено, ссылки на объекты не выходят за иерархии вызовов, то эти объекты автоматически будут размещаться в стеке.
Ну, а в С++ и без всяких аллокаторов можно вручную размещать объекты в стеке.
V> Если подобные задачи покажутся слишком редкими и специфическими, то я не соглашусь с этим. Очень во многих задачах не принципиален порядок уничтожения объектов и часто можно весьма безболезненно сделать так, чтобы объекты преимущественно удалялись в удобном нам порядке.
Тут оно как. Или ты пишешь программу, или занимашся оптимизациями. Так вот ЖЦ можно рассматривать как автоматическое средство глобальной оптимизации.
V> Именно тут мне видится наибольшая польза от возможности ручного управления памятью. Этой возможностью мне приходилось в свое время очень успешно пользоваться, благодаря чему производительность увеличивалась на порядки (узким местом был именно хип)
Увеличить производительность на порядки можно просто использовав более подходящие алогоритмы. Управление памятью на основе ЖЦ и так имеет характеристику блызкую к O(1) (т.е. линейную зависимость).
Так вот рельно лучше сосредоточиться на оптимизации прикладных алгоритмов, а не на оптимизации системных вещей вроде выделения памяти. В будущем, когда появятся более эффективные методы автоматической оптимизации можно будет извлечь из них выгоду.
Единственное где ЖЦ реально проигрывает ручному управлению памятью — это в условиях когда памяти катастрофически нехватает. Почти все ЖЦ-алогоритмы рассчитаны на наличие большего объема памяти чем реально требуется по минимуму.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, eao197, Вы писали:
E>Если это менеджер, который не выделяет память динамически, а использует заранее выделенные буффера памяти, то на ряде задач вполне себя оправдает.
Большинство реализаций ЖЦ как раз так и поступают. Так что "все украдено до нас".
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
V>> Никакой универсальный ГЦ или хип не сравнятся на этой задаче с тривиальным менеджером памяти на циклическом буффере.
VD>Можно сслочку на то, где ты видел подобные решения в реальной жизни? Сколько таких случаев было?
Стандартный хип на таких обьемах уже не просто тормозил, но и не мог выдать требуемое число блоков. Тогда я написал свой собственный менеджер памяти, и все стало ок.
Здравствуйте, eao197, Вы писали:
E>И кстати, об удобстве. Когда-то в исходниках редактора cooled (из Midnight Commander-а) видел такой фокус по динамическому распределению памяти. Во многих функциях требовалось распределить динамически память, сохранить туда какую-нибудь строку и вернуть указатель на эту память куда-то наверх. Чтобы не заморачиваться с владением памяти и ответственностью за ее удаление, в cooled был применен простой хак. Для выделения такой памяти использовалась специальная функция (названия не помню, пусть будет get_temp_mem()), которая внутри себя владела очередью указателей (на обычном векторе). Как только требовалось память, она выделялась и указатель на нее помещался в данную очередь, после чего возвращался из get_temp_mem(). При этом, если в очереди оказывалось N+1 элементов, то самый старый из них просто удалялся из очереди, а его память освобождалось. Все это работало в предположении, что в один момент времени в программе не может жить больше, чем N указателей, возвращенных get_temp_mem().
IMHO это безобразие не стоит упоминания в разговоре про аллокаторы STL.
VladD2 wrote: > E>Если это менеджер, который не выделяет память динамически, а > использует заранее выделенные буффера памяти, то на ряде задач вполне > себя оправдает. > Большинство реализаций ЖЦ как раз так и поступают. Так что "все украдено > до нас".
Зато во время сборки ГЦ имеют обыкновение периодически сканировать
память, причем несовсемтимо с realtime'ом.
А с realtime-GC уже радужная картина с "простым увеличением указателя на
свободное место" пропадает.
Здравствуйте, Kluev, Вы писали:
VD>>Можно сслочку на то, где ты видел подобные решения в реальной жизни? Сколько таких случаев было?
K>Хотите раельных программ? Их есть у меня.
K>http://www.qform3d.com/en/91.html — использует рукописный (мой) менеджер памяти.
404 Not Found
K>Стандартный хип на таких обьемах уже не просто тормозил, но и не мог выдать требуемое число блоков. Тогда я написал свой собственный менеджер памяти, и все стало ок.
Сейчас тебе расскажут, что ты исключение подтверждающее правило
Здравствуйте, Cyberax, Вы писали:
C>Зато во время сборки ГЦ имеют обыкновение периодически сканировать C>память, причем несовсемтимо с realtime'ом.
Какой на фиг реалтайм под Виндовс? Что ты к нему цепляшся. Ты хоть одну программу реального времени написал?
C>А с realtime-GC уже радужная картина с "простым увеличением указателя на C>свободное место" пропадает.
Не о собых проблем с realtime-GC. Просто у оного класса алгоритмов свои особенности.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Kluev, Вы писали:
K>Хотите раельных программ? Их есть у меня.
K>http://www.qform3d.com/en/91.html — использует рукописный (мой) менеджер памяти.
K>Стандартный хип на таких обьемах уже не просто тормозил, но и не мог выдать требуемое число блоков. Тогда я написал свой собственный менеджер памяти, и все стало ок.
И где гарантия, что твое решение не является в пустую потраченным временем по сровнению с банальным выбором ЖЦ?
В общем, не нужно тыкать в свой код. Ты мне тыкни во всем известные примеры промышленного использования.
Я вот видил пару оптимизаций в соей жизни. И весе они без проблем заменялись бы ЖЦ. Вот к примеру, компилятор C# (MS-ный) использует пул для каких-то тама оптимизаций. Вот только пул ничем не отличается от ЖЦ основанного на поколения с точки зрения скорости.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, igna, Вы писали:
I>А вдруг? А может это и вовсе одно и то же сообщение выводимое 10000000 раз в секунду, чтобы поиздеваться над сборщиком мусора?
using System;
using System.Diagnostics;
class Program
{
static char[] _array;
static void Main()
{
Stopwatch timer = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
_array = new char[100];
_array = null;
}
Console.WriteLine(timer.Elapsed);
for (int i = 0; i <= GC.MaxGeneration; i++)
Console.WriteLine("Количество сборок в поколнии {0}: {1}", i, GC.CollectionCount(i));
}
}
В релизе не из под отладчика на AMD 64 3500+:
00:00:00.6544834
Количество сборок в поколнии 0: 8084
Количество сборок в поколнии 1: 0
Количество сборок в поколнии 2: 0
Еще вопросы есть?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Kluev, Вы писали:
K>Здравствуйте, alexeiz, Вы писали:
A>>... я могу смело сказать, что С++ в Майкрософте остановился на уровне 94 года (т.е. STL'ом там и не пахнет, хорошо хоть шаблоны попадаются изредка).
K>Вот и хорошо что там не пахнет STL-ем. Запаха МФЦ вполне достаточно, а если еще и запах STL... нет это уже перебор.