Общая собственность редко имеет смысл
Этот ответ может быть немного несоответствующим, но я должен спросить, сколько случаев имеет смысл с точки зрения пользователя разделять владение ? По крайней мере, в доменах, в которых я работал, их практически не было, потому что в противном случае это означало бы, что пользователю не нужно просто удалять что-то один раз из одного места, а явно удалять это от всех соответствующих владельцев, прежде чем ресурс действительно будет удален из системы.
Часто это инженерная идея более низкого уровня, которая предотвращает уничтожение ресурсов, пока к ним все еще кто-то обращается, например, другой поток. Часто, когда пользователь просит закрыть / удалить / удалить что-то из программного обеспечения, его следует удалить как можно скорее (когда это безопасно удалить), и это, безусловно, не должно задерживаться и вызывать утечку ресурсов до тех пор, пока приложение работает.
Например, игровой актив в видеоигре может ссылаться на материал из библиотеки материалов. Мы, конечно, не хотим, скажем, сбоя висящего указателя, если материал удален из библиотеки материалов в одном потоке, в то время как другой поток все еще получает доступ к материалу, на который ссылается игровой актив. Но это не значит, что игровым активам не имеет смысла делиться правами собственности на материалы, на которые они ссылаются, с библиотекой материалов. Мы не хотим заставлять пользователя явно удалять материал из библиотеки ресурсов и материалов. Мы просто хотим убедиться, что материалы не будут удалены из библиотеки материалов, единственного разумного владельца материалов, до тех пор, пока другие потоки не закончат доступ к материалу.
Утечки ресурсов
Тем не менее, я работал с бывшей командой, которая использовала GC для всех компонентов программного обеспечения. И хотя это действительно помогло убедиться, что у нас никогда не было уничтоженных ресурсов, в то время как другие потоки все еще обращались к ним, мы вместо этого получили свою долю утечек ресурсов .
И это были не тривиальные утечки ресурсов, которые расстраивают только разработчиков, например, утечка памяти в килобайтах после часового сеанса. Это были эпические утечки, часто гигабайты памяти во время активного сеанса, что приводило к сообщениям об ошибках. Потому что теперь, когда ссылка на владение ресурсом (и, следовательно, на него делятся владениями), скажем, между 8 различными частями системы, требуется только один, чтобы не удалить ресурс в ответ на запрос пользователя об удалении его для него. быть утечкой и, возможно, на неопределенный срок.
Так что я никогда не был большим поклонником GC или подсчета ссылок, применяемых в широком масштабе, потому что им было легко создавать утечку программного обеспечения. Раньше было бы зависание свисающего указателя, которое легко обнаружить, превращается в очень трудно обнаруживаемую утечку ресурса, которая может легко попасть под радар тестирования.
Слабые ссылки могут смягчить эту проблему, если язык / библиотека предоставляют их, но я обнаружил, что команде разработчиков смешанных наборов навыков трудно постоянно использовать слабые ссылки в случае необходимости. И эта проблема была связана не только с внутренней командой, но и с каждым разработчиком плагинов для нашего программного обеспечения. Они также могут легко вызвать утечку ресурсов в системе, просто сохраняя постоянную ссылку на объект таким образом, что затрудняется отследить плагин как виновника, поэтому мы также получили львиную долю сообщений об ошибках, полученных из наших программных ресурсов. утечка просто потому, что плагин, чей исходный код был вне нашего контроля, не смог выпустить ссылки на эти дорогие ресурсы.
Решение: отложено, периодическое удаление
Поэтому позднее мое решение, которое я применил к своим личным проектам, которые дали мне лучшее из того, что я нашел в обоих мирах, заключалось в устранении концепции, которая, referencing=ownership
тем не менее, отложила уничтожение ресурсов.
В результате, теперь, когда пользователь делает что-то, что приводит к необходимости удаления ресурса, API выражается в терминах простого удаления ресурса:
ecs->remove(component);
... которая моделирует пользовательскую логику очень простым способом. Тем не менее, ресурс (компонент) не может быть удален сразу же, если есть другие системные потоки в их фазе обработки, где они могут одновременно обращаться к одному и тому же компоненту.
Таким образом, эти потоки обработки тут и там дают время, которое позволяет потоку, похожему на сборщик мусора, просыпаться и « останавливать мир » и уничтожать все ресурсы, которые были запрошены для удаления, при этом блокируя потоки от обработки этих компонентов, пока он не завершится. , Я настроил это так, чтобы объем работы, который необходимо выполнить здесь, был, как правило, минимальным и не оказывал заметного влияния на частоту кадров.
Сейчас я не могу сказать, что это какой-то проверенный и хорошо документированный метод, но я уже несколько лет использую его без головной боли и утечек ресурсов. Я рекомендую исследовать подходы, подобные этому, когда ваша архитектура может соответствовать такой модели параллелизма, поскольку она намного менее сложна, чем сборщик мусора или повторный подсчет, и не рискует утечек этих типов ресурсов, попадающих под радар тестирования.
Единственное место, где я нашел повторный подсчет или GC, полезно для постоянных структур данных. В этом случае это территория структуры данных, далеко оторванная от интересов конечного пользователя, и там действительно имеет смысл для каждой неизменной копии иметь потенциальное совместное владение одними и теми же неизмененными данными.