Постулат №1:
GC это хорошо и malloc/free тоже хорошо.
В поисках идеала (для UI programing) пришел к следующему выводу:
GC как средство макроменеджмента памяти это то что нужно.
GC как средство микроменеджмента памяти это дрова.
Микроменеджмент памяти это прерогатива malloc/free и stack allocation.
Что есть macro и micro management? Поясню на примере:
Классический () подход современных Java или WinForms.net:
Скажем для того чтобы залить прямоугольгик каким-нибудь цветом мы имеем:
class Brush { Color color; ... }
class Graphics
{
void fillRect( Rect r );
}
Brush b = new Brush( new Color(0xFF,0,0) );
Rect r = new Rect( 10,10,100, 100 );
gfx.setBrush(b);
gfx.fillRect(r);
В данном случае Java выполняет менджмент микро объектов Rect и Brush — создает и удаляет их. Как следствие система жутко не эффективная. Как правило Brush это обертка над системным HBRUSH в конце концов. Т.е. к тому же имеем еще и dispose со всеми вытекающими.
Brush как отдельный объект никому не нужен. Как правило все что с ним делается это вызывается конструктор и все.
Rectangle в общем-то тоже как самостоятельный объект представляет мало ценности. Тогда зачем они? (см. далее про j-smile)
Постулат №2:
Если некая GC система (runtime например) требует интенсивного explicit dispose это
означает ошибку в дизайне этой самой системы/runtime.
Код требующий dispose нужно выносить на уровень микроменеджмента.
Что я попытался сделать в j-smile (микро/макро был одной из основных идей дизайна):
тот же фрагмент кода выглядит так:
// class Brush { Color color; ... } - просто нет этого как сущности
// Color тоже нет. Вернее есть, но не как объект, а namespace для стат. функций. class Graphics
{
void fillRect( int x, int y, int w, int h );
}
gfx.setBrush(Color.RGB(0xFF,0,0));
gfx.fillRect(10,10,100, 100);
Менеджмент HBRUSH и всего такого (микроменеджмент) выполняет
С имплементация класса Graphics. Заведомо максимально эффективным образом.
Java же управляет макро объектами Windget, Widgets (container) и т.д.
Все вместе а) значительно снижает нагрузку на GC (мало объектов — мало мусора)
b) значительно снижает требования к самой VM Java — все интенсивные
вычисления делаются на стороне C.
Если посомтреть то j-smile-demo.exe
(самописная VM + copying GC) тактильно работает в общем-то c той же скоростью что
и Harmonia примеры ( D c крутым codegen ). И объем exe в общем-то идентичен.
j-smile-demo.exe это двоичный bundle: 200k(VM+runtime) + 200k bytecodes (noncompressed .class files)
Откомпилированные D самплы по размеру бинарников соизмеримы.
Постулат №3
Оптимальная система оптимально использует разные
механизмы memory managment.
"Все — managed" это имхо грубейшая ошибка дизайна которая например убила Java UI на корню.
.NET UI (WinForms) слепо содрав подход AWT/SWT успешно двигается в
том же самом направлении.
Вот такие вот мои мысли в слух если они кому интересны.
CS>"Все — managed" это имхо грубейшая ошибка дизайна которая например убила Java UI на корню.
разработчики Java UI (swing) неправильно оценили свою задачу. Они создавали swing не как базовую библиотеку, а как обычный проект из некоторой предметной области.
Тому, кто будет использовать библиотеку позволительно меньше задумываться о ресссурсах и больше сосредоточится на предмете
Поэтому грамотное написании базовой библиотеки нацелено прежде всего на удобство использования, экономичность и максимально высокую производительность. У тех кто разрабатывал swing этого понимания небыло.Так и плодятся самые разные проекты . Архитектурно гараздо более удачные.
CS>.NET UI (WinForms) слепо содрав подход AWT/SWT успешно двигается в
и это правда
CS>том же самом направлении.
CS>Вот такие вот мои мысли в слух если они кому интересны.
очень интересно, надо бы с тобой поближе познакомиться
Здравствуйте, c-smile, Вы писали:
CS>В данном случае Java выполняет менджмент микро объектов Rect и Brush — создает и удаляет их.
Rect в .NET — это value type. Соответственно GC тут не при чём. Проблема с Brush только одна — его нужно диспозить. Занимаемая ею память на эффективность программы никак не повлияет. Ну запустится GC не три раза за время работы программы, а четыре
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, c-smile, Вы писали:
CS>>В данном случае Java выполняет менджмент микро объектов Rect и Brush — создает и удаляет их.
IT>Rect в .NET — это value type. Соответственно GC тут не при чём.
Да в .NET c этим чуть лучше. Но не радикально.
IT>Проблема с Brush только одна — его нужно диспозить. Занимаемая ею память на эффективность программы никак не повлияет.
И я о том. А зачем собственно. Говоря о brush, кому-нибудь нужна эта самая brush как объект с атрибутами? Вряд ли.
А в тех случаях когда да, то сделать себе простой value тип — описатель — три секунды.
IT> Ну запустится GC не три раза за время работы программы, а четыре
При отработке события WM_PAINT jsmile-demo.exe вообще ничего не аллоцирует в Java коде ибо не требуется.
CS>Постулат №3 CS>Оптимальная система оптимально использует разные CS>механизмы memory managment. CS>"Все — managed" это имхо грубейшая ошибка дизайна которая например убила Java UI на корню. CS>.NET UI (WinForms) слепо содрав подход AWT/SWT успешно двигается в CS>том же самом направлении.
У O'Camla тут интересное решение в виде двух куч — малой, для короткоживущих объектов. И большой — понятно для чего.
+ Естественно, все достаточно маленькие значения он кладет туда, куда нужно сразу.
Каким-то образом это пересекается с идеей регионов у cyclone — там нечто вроде стека из куч
Еще очень интересное направление — это region inference, когда копилятор статически определяет все точки на стеке, где есть ссылка на объект и освобождает память там, где объект выходит за пределы видимости.
Я боюсь, что просто разделения managed-unmanaged в 2005 году уже недостаточно — детали, все решают детали
reductor wrote:
> У O'Camla тут интересное решение в виде двух куч — малой, для > короткоживущих объектов. И большой — понятно для чего.
Боже мой! Это "интересное решение" давно уже используется в мире
Java/C#, называется "generational garbage collection". Причем намного
эффективнее, чем в OCaml'е.
А если бы вы удосужились прочитать ту ссылку на старую тему на RSDN,
которую я давал вам, то и таких вопросов бы не возникало.
Кстати, даже консервативный Boehm GC поддерживает сборку в разных
поколениях.
> Каким-то образом это пересекается с идеей регионов у cyclone — там > нечто вроде стека из куч > Еще очень интересное направление — это region inference, когда > копилятор статически определяет все точки на стеке, где есть ссылка на > объект и освобождает память там, где объект выходит за пределы видимости.
Здравствуйте, Cyberax, Вы писали:
C>Боже мой! Это "интересное решение" давно уже используется в мире C>Java/C#, называется "generational garbage collection". Причем намного C>эффективнее, чем в OCaml'е. C>Читать ХОТЯ БЫ http://www.codeproject.com/dotnet/garbagecollection.asp . C>А если бы вы удосужились прочитать ту ссылку на старую тему на RSDN, C>которую я давал вам, то и таких вопросов бы не возникало. C>Кстати, даже консервативный Boehm GC поддерживает сборку в разных C>поколениях. C>Это элементарно делается с помощью пулов, временем жизни которых C>управляет автоматическая переменная на стеке. Применительно к Java это C>сделано в http://www-rocq.inria.fr/arles/doc/ps02/RT-journal.pdf .
Так, на секундочку, вам не кажется, что вы немножко не на то сообщение ответили?
Или что не прочитали перед тем как отвечать, уж не знаю.
Просто буря какая-то эмоций.
В случае с окамлом и с другими, смысл в том, что как время жизни и прочее определяется _статически_ компилятором.
И что окамл кладет значения не только на кучу.
А что inria (институт, в котором делают ocaml) много технологий родила и для java много делает я в курсе.
Сам Xavier Leroy много где в java-технологиях отметился.
reductor wrote:
> В случае с окамлом и с другими, смысл в том, что как время жизни и > прочее определяется _статически_ компилятором. > И что окамл кладет значения не только на кучу.
А это называется escape analysis, и тоже замечательно используется в
Java/C# (а в С++ заменяется автоматическими объектами). Причем в новой
Java Hotspot JVM 1.6 оно еще будет привязано к механизму hotspot.
> А что inria (институт, в котором делают ocaml) много технологий родила > и для java много делает я в курсе.
Generational GC примерно лет на 15 старше OCaml'а.
Здравствуйте, Cyberax, Вы писали:
C>reductor wrote:
>> В случае с окамлом и с другими, смысл в том, что как время жизни и >> прочее определяется _статически_ компилятором. >> И что окамл кладет значения не только на кучу.
C>А это называется escape analysis, и тоже замечательно используется в C>Java/C# (а в С++ заменяется автоматическими объектами). Причем в новой C>Java Hotspot JVM 1.6 оно еще будет привязано к механизму hotspot.
Ну и? Тема-то текущая про что вообще? Или вы по интерции?
>> А что inria (институт, в котором делают ocaml) много технологий родила >> и для java много делает я в курсе.
C>Generational GC примерно лет на 15 старше OCaml'а.
Во-первых, не на 15.
Во-вторых, у O'Caml не просто Generational GC
В-третьих, тут в данной ветке речь не о том, а посмотрите о чем.
Здравствуйте, reductor, Вы писали:
R>У O'Camla тут интересное решение в виде двух куч — малой, для короткоживущих объектов. И большой — понятно для чего. R>+ Естественно, все достаточно маленькие значения он кладет туда, куда нужно сразу.
...
Мой пост немного о другом.
Есть объекты с детерминирванным временем жизни.
Детерменированность как информация это то качество которое мы теряем
при отданнии их на откуп GC.
В целом система получается неоптимальной.
Есть задачи в которых "только GC" (generational или нет, не важно)
работает. Но задачи UI не из их числа. Там нужно оба подхода.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, c-smile, Вы писали:
CS>>При отработке события WM_PAINT jsmile-demo.exe вообще ничего не аллоцирует в Java коде ибо не требуется.
IT>А для .NET версия есть?
Нет. И я задачи такой не ставил. j-smile делался мной когда на
меня нагрузили руководство созданием системы с Java UI.
Т.е. в том числе я пытался понять как оно там внутри работатет.
Вторая гипотеза которая проверялась — можно ли сделать
встраиваемую VM чтобы не заморачиваться проблемами
совместимости с установленными JRE.
Ну и про третью я уже сказал. Память и работа с ней.
Здравствуйте, c-smile, Вы писали:
CS>Есть объекты с детерминирванным временем жизни. CS>Детерменированность как информация это то качество которое мы теряем при отданнии их на откуп GC.
Не могу согласиться с этим утверждением. Время жизни объектов в системах с GC вполне детерминировано и определяется наличием живых ссылок на этот объект.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, c-smile, Вы писали:
CS>>Есть объекты с детерминирванным временем жизни. CS>>Детерменированность как информация это то качество которое мы теряем при отданнии их на откуп GC.
IT>Не могу согласиться с этим утверждением. Время жизни объектов в системах с GC вполне детерминировано и определяется наличием живых ссылок на этот объект.
Это не та детерминированность. Для большой группы объектов в UI время жизни
известно заранее, это например все случаи RAII:
window::draw()
{
graphics gx(this);
....
рисуем
....
забываем что было такое gx.
}
graphics это не GC объект, а явно стековый.
Вторая группа объектов это те про которые GC и знать не надо.
Например:
class Graphics {
native void setFont(String name, int size, boolean bold, boolean italic)
}
внутри таблица шрифтов это например статическая хеш таблица.
Эта самая таблица не нужна GC ни в каком виде, а наоборот — только мешает.
Немного вне темы:
Java и его JNI мне представляется более разумной моделью изоляции GC/не-GC
чем MC++. MC++ это вообще каша какая-то с непонятным назначением и неясной моделью vm.
JNI прост как двери, естественен и никакого насилия над личностью — котлеты — отдельно,
инсекты — отдельно.
Здравствуйте, c-smile, Вы писали:
CS>В данном случае Java выполняет менджмент микро объектов Rect и Brush — создает и удаляет их. Как следствие система жутко не эффективная. Как правило Brush это обертка над системным HBRUSH в конце концов. Т.е. к тому же имеем еще и dispose со всеми вытекающими. CS>Brush как отдельный объект никому не нужен. Как правило все что с ним делается это вызывается конструктор и все. CS>Rectangle в общем-то тоже как самостоятельный объект представляет мало ценности. Тогда зачем они? (см. далее про j-smile)
Я так понимаю, что в .Net и Brush и Rectangle — value типы. Которые сделаны как раз для того, чтобы не напрягать GC. Имеем честную стековую аллокацию, прозрачную интеграцию c GC (структуры, лежащие в стеке, могут быть корнями для reference — объектов), возможность пользоваться методами, в том числе и виртуальными. Благодаря этому, эффективность метода, использующего новый Brush, вряд ли ниже его pure-C аналога. Потому что ничего лишнего не делается.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Все слова про объекты и их экономию просто смехотворны. За время отрисовки таких объектов может возникнуть, ну, десятки, ну, сотни, в параноидальных случаях тысячи. Все это для GC не цифры.
Другое дело ручное управление ресурсами. Вот тут я соглашусь, что лучше бы чтобы все ресурсы ОС освобождались бы одним вызовом. Но для этого совершенно не нужно скрывать объекты в недрах того же Graphics. Это ведь порождает очень некрасивый структурный (не ОО) код и проблемы с производительностью, так как повторное создание хэндлов в ОС отнюдь не дешево.
Я вот опробовал другую идею. В Graphics кэшируются реальные ресурсы выделяемые ОС. А все объекты вроде Font, Brash и т.п. только хранят их описание. Внутри Graphics имеются банальные хэш-таблицы ассоциирующие эти объекты с хэндлами ОС. Причем ассоциирующие по значению, а не по ссылке, так что два одинаковых по описанию фрифта будут ассоциированны с единым хэндлом. В Dispose() Graphics-а происходит перебор этих хэш-таблиц и освобождение ресурсов. В итоге скорость отрисовки ничем не отличается от твоего варианта, но при этом код можно писать в ОО-стиле не заморачиваясь переходом к откровенно С-шному стилю программирования.
За одно решается целый рад проблем, вроде устранения повторного создания и выбора в DC хэндлов ОС.
Код же при этом получается даже проще чем в GDI+ (за счет того, что не нужно делать диспозы всем вспомогательным объектам).
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, c-smile, Вы писали:
CS>Brush
Сыплю. Лень было проверить.
Однако первый же взгляд туда выдает причины, по которым кисть таки не сделали структурой: от нее пять наследников, а вэлью-типы не поддерживают полиморфизм.
Тут возникает такой занятный вопрос — а как добиться в твоем коде эффекта, аналогичного, к примеру, LinearGradientBrush?
Тут одним static class Color не обойдешься.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, c-smile, Вы писали:
CS>>Brush S>Сыплю. Лень было проверить. S>Однако первый же взгляд туда выдает причины, по которым кисть таки не сделали структурой: от нее пять наследников, а вэлью-типы не поддерживают полиморфизм.
1) А зачем там полиморфизм?
2) Базовые примитивы UI должны быть максимально эффективными.
3) Если нужно нечто выдающееся, например для векторной графики, то делают GraphicsEx
со всеми наворотами, рисованием в буфер и пр. Но не стреляют главным калибром по воробьям.
То что графика в .NET "сакс" это не я придумал.
Т.е. она идеологически правильная но практически не работает — тормозит.
S>Тут возникает такой занятный вопрос — а как добиться в твоем коде эффекта, аналогичного, к примеру, LinearGradientBrush? S>Тут одним static class Color не обойдешься.
Посмотри на список конструкторов. В моем случае это
будет простой набор методов
Graphics.setGradientBrush(...) Это если оно надо.
Полиморфизм вещь хорошая, но там где он нужен. Все — в меру. Как всегда.