Я знаю, что могу получить много отрицательных ответов за этот ответ, но если вы уже пытаетесь избежать динамической памяти, в первую очередь, потому что вы сказали, что нет-нет, почему вы вообще используете GC? Я бы никогда не использовал GC в системе реального времени, где предсказуемое быстродействие является главной задачей. Я бы избегал динамической памяти везде, где это возможно, таким образом, есть очень, очень мало динамических объектов для начала, а затем я бы обрабатывал очень мало динамических выделений, которые у меня есть, поэтому у меня есть 100% контроль, когда что-то выпущено и где оно находится вышел. В конце концов, не только GC не является детерминированным, free () так же мало детерминирован, как и malloc (). Никто не говорит, что вызов free () просто должен пометить память как свободную. С таким же успехом он может попытаться объединить меньшие блоки свободной памяти, окружающие free'd, в один, и это поведение не является детерминированным и не является для него временем выполнения (иногда free не делает этого, а malloc делает это вместо этого в следующем выделение, но нигде не написано, что бесплатные не должны этого делать).
В критической системе реального времени вы можете даже заменить системный стандарт malloc () / free () другой реализацией, возможно даже написать свою собственную (это не так сложно, как кажется! Я делал это раньше, просто в шутку) это работает наиболее детерминистично. Для меня GC - удобная штука: она отвлекает программистов от необходимости сосредоточиться на сложном планировании malloc () / free () и вместо этого заставляет систему автоматически справляться с этим. Это помогает выполнять быструю разработку программного обеспечения и экономит часы отладки при поиске и устранении утечек памяти. Но точно так же, как я бы никогда не использовал GC в ядре операционной системы, я бы никогда не использовал его в критических приложениях реального времени.
Если мне понадобится более сложная обработка памяти, я, возможно, напишу свой собственный malloc () / free (), который работает как нужно (и наиболее детерминировано), и напишу поверх него свою собственную модель подсчета ссылок. Подсчет ссылок по-прежнему является ручным управлением памятью, но гораздо удобнее, чем просто использование malloc () / free (). Он не сверхбыстрый, но детерминированный (по крайней мере, увеличение / уменьшение счетчика ссылок является детерминированным по скорости), и если у вас не будет циклических ссылок, он перехватит всю мертвую память, если вы будете следовать стратегии сохранения / освобождения во всем приложении. Единственная недетерминированная часть в том, что вы не будете знать, вызовет ли релиз release просто уменьшит ли счетчик ссылок или действительно освободит объект (в зависимости от того, станет ли счетчик ссылок нулевым или нет), но вы можете отложить фактическое освобождение, предложив Функция сказать «releaseWithoutFreeing», которая уменьшает счетчик ссылок на единицу, но даже если он достигнет нуля, он еще не освободит () объект. Ваша реализация malloc () / free () может иметь функцию «findDeadObjects», которая ищет все объекты с нулевым счетчиком сохранения, которые еще не были освобождены, и освобождает их (в более поздний момент, когда вы находитесь в менее критическом состоянии). часть вашего кода, которая имеет больше времени для таких задач). Поскольку это также не является детерминированным, вы можете ограничить количество времени, которое он может использовать для этого, например «findDeadObjectsForUpTo (ms)», а ms - это количество миллисекунд, которое он может использовать для их поиска и освобождения, возвращаясь, как только на этот раз Квант был использован, так что вы не будете тратить слишком много времени на эту задачу.