Цитата:
Rust не для тех, кто хочет работать в предметной области, и поэтому он мне не нравится. Не хочу думать про сборку мусора, например.
Так что может для профессиональных программистов — это хороший язык, а для меня он не лучше C.
MultiOberon тоже LLVM умеет теперь, который обеспечивает скорость для Rust.
Но в Rust-е пока не внедрён сборщик мусора ("box"-ы на основе GC, имевшее место когда-то в ранних версиях до релиза, пока выпилены до лучших времён).
Во время последнего из опубликованных докладов Дня Оберона (про "метапрограммирование") была фоновая реплика от Недори насчёт
языка Jai (обращал внимание на организацию вычислений в compiletime, а также в его заметках есть акцент на Jai как пример решения проблематики ООП). Язык декларируется как замена С в области gamedev-а. Там принципиально отказываются от сборщика на уровне "философии языка", мусорщик не решает проблем в этой предметке ("video games are machines that fill memory", "data-oriented programming"), но создаёт новые ("language features like garbage collection and templated data streams and dynamic string classes may help the programmer write code faster, but they don’t help the programmer write faster code"). Используются
"владеющие" указатели, custom-аллокаторы, инициализация по умолчанию,
Data-Oriented Structures (с возможностью автоматической (на уровне типа) конвертации из массива структур в структуру массивов),
Joint Allocations (может быть и какие-то иные техники, но необходимо изучать многочасовые видео-материалы).
В Java, например, наблюдается весьма любопытный эксперимент для задач "Big Data" -- на основе существующих алгоритмов HotSpot (и без изменения в языке, как альтернатива использованию внешних heap) внедряется возможность организации множества динамических "поколений" (в дополнение к традиционным двум old и young) для уменьшения количества операций копирования объектов между "поколениями", фактически, косвенно вводится тот же custom-аллокатор (добавляется небольшой API и аннотации к операции new):
*
NG2C: Pretenuring Garbage Collector with Dynamic Generations for HotSpot Big Data Apps*
ПрезентацияНа форуме недавно была ссылка на полезный доклад о проблемах сборщика, от товарища-разработчика из Excelsior, где акцентируется на смене их технологии -- после многолетнего применения "консервативной" модели вынуждены были перейти к "точной" (затруднительно в "консервативщине" обеспечить корректность и не допускать "мертвецов", да и при "точной" модели не обойтись без всяких ручных дёргалок вокруг сборщика и помогалок вида "слабых" ссылок аля java.lang.ref), с увеличенными затратами (из-за save point и прочие барьеры записи/чтения):
https://forum.oberoncore.ru/viewtopic.php?f=22&t=6529&sid=3c963af72aca980f0b6fe68041ca5eb1#p110604В докладе отмечается, что, всё же, вынужденны отказываться от некоторых оптимизаций кода, однако без конкретики. По поводу вспоминается старенькая статейка насчёт экспериментов вокруг Modula 3, где был акцент на проблематике этапа сканирования -- либо не допускать некоторые оптимизации, либо сканирование -- дело непростое, например:
A Language-Independent Garbage Collector ToolkitЦитата:
The stack map is necessary but not sufficient for stack and register decoding in the presence of optimizations. For example, if a procedure has many uses of the expression A[i-100], the optimizer may calculate the address of A[-100] and use it as a base for address calculations. If the array A is in the heap and a scavenge occurs, we must properly update the base register. We use the term attached pointers for pointers attached to heap objects in this way. To handle attached pointers we augment the map to indicate what the pointer is attached to (A in this case). At scavenge time the attached pointer is converted to an offset, then at the end of the scavenge, the offset is converted back into a pointer. A similar example arises when two arrays are frequently indexed by the same value, e.g., A[i] and B[i]. It can be more efficient on some architectures to calculate the difference B - A of the addresses of A and B, with B[i] accessed via double indexing from A[i]. The difference is an example of a derived pointer value. Such derived values can be noted in the map and recalculated after a scavenge. It is also possible for derived values to be calculated differently on different paths in a program, which requires a small amount of work at run-time so that the collector can determine which derivation was actually used. Finally, parameters passed by reference lead to pointers into the middle of objects. These are handled similarly to attached pointers. The only differences are that the attachment crosses procedure boundaries so caller help is required, and we can end up with long chains of attachments through many levels of call.
К слову, в статейке выше ещё в те года (начало 90-х) предлагалось автоматически множество поколений (меньше копирования и лучше дефрагментация).
В докладе от Excelsior упоминается и проблематика финализаторов, несмотря на объявление их как deprecated отказаться и выпилить их, фактически, невозможно. Ещё в начале 2000-х была статья от товарища Boehm (не случайный человек в сфере мусорщиков), где он указывал прежде всего на изначально кривой дизайн этих финализаторов в Java и C# (в статейке затрагивается и универсальная сборка на "reference counter", также имеющая проблемы с деструкторами в общем случае), и показал, что в той же Modula 3 решения были куда "прямее" (напр., в Modula осуществлялось упорядочивание исполнения финализаторов на основе зависимости между объектами, выявляемой косвенно -- объект может содержать ссылки на другие объекты, но не использовать их в финализаторе):
*
Destructors, Finalizers, and Synchronization*
ПрезентацияВ статейке Boehm упоминает и про некоторые оптимизации от компиляторов, которые могут привести к некорректной отработке финализаторов.
В соседнем разделе форума есть тема про Esterel, где встречаются материалы и про Real Time Java, там наблюдаются немалые ухищрения для сборщика (если он допустим), чтобы обеспечить этот Real Time. Последствия могут быть даже такие, как, напр., трансформация стандартных массивов в некое виртуальное понятие -- далеко не всегда массив может быть выделен как непрерывный блок памяти (деятельность сборщика/аллокатора должна предполагать возможность крайне высокой "инкрементальности" -- очень частое прерывание своей работы (и обеспечение прикладной и прочей системной активности) и непрерывное управление дефрагментацией). Соответственно возникают нюансы и при взаимодействии с С-окружением и т.д.
Видимо, в целом способ управления памятью -- ключевая штуковина, фундаментально определяющая всю архитектуру ПО, его структуру и свойства.