Воскресенье, 17 Ноября 2024, 15:26

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Сборка мусора(С++)
НохчиДата: Воскресенье, 19 Мая 2013, 20:14 | Сообщение # 1
заслуженный участник
Сейчас нет на сайте
Всем доброго времени суток.
Потребовалось написать менеджер ресурсов, работающий по следующему принципу:
Информация обо всех используемых в программе ресурсах хранится во внешнем файле, разумеется грузить их все сразу смысле нет - различные ресурсы(тесктуры/музыка/шрифты) используются на разных этапах работы программы. К тому же, после отработки очередного этапа множество ресурсов надолгое время становятся ненужными. Соотвественно нужно
a)загружать ресурс при первом запросе со стороны какого-нибудь объекта
b)выгружать, когда ни один объект больше ресурсом не пользуется
Со-вторым пунктом сложности. Нужно каким-то образом узнать, что все ссылки на ресурс потеряны. Конечно же в голову пришли умные указатели с подсчетом ссылок. Но как это грамотно реализовать не знаю. Вижу два варианта:
1)Менеджер хранит внутри себя shared_ptr на ресурс, который возвращается при запросе ресурса(соответственно увеличивается счетчик ссылок). Когда какой-либо объект запросивший ресурс уничтожается, уничтожается и его экземпляр shared_ptr, и счетчик ссылок уменьшается. Соответственно, когда все объекты пользовавшиеся ресурсом будут удалены, счетчик ссылок будет равен 1(shared_ptr из самого менеджера). Если бы можно было заставить объект удаляться при счетчик равному 1, а не 0, было бы прекрасно. Но в нашем случае придется через какие-то промежутки времени вручную вызывать метод сборки мусора и проверять
Код
if(ptr->use_counter() == 1) delete ptr;

А это лишняя куча кода и вообще костыль.

2)Мы все так же возвращаем объектами требующим ресурс shared_ptr на него. Но в данном случае внути самого менеджера этот указатель не храним, вместо этого используется своя схема подсчета ссылок на ресурс. Таким образом при удалении каждого объекта, который запрашивал ресурс, будет вызван функтор удаления ресурса, внутри которого мы проверяем наш самопальный счетчик и если он равен нулю, удаляем ресурс. Код демоснтрирующий это на пастебин

В общем, тоже странная вещь у меня получается. На каждый ресурс затычки вроде
Код

struct ResTexture
{
  Texture texture;
  unsigned int use_count;
};

struct ResSound
{
  Sound sound;
  unsigned int use_count;
};

struct ResFont
{
  Font font;
  unsigned int use_count;
};

В общем, глаз замылился уже. Кажется, что какие-то очевидные вещи упускаю.

У кого какие мысли?


Многие вопросы по Windows отпадут, если посмотреть тут
nilremДата: Воскресенье, 19 Мая 2013, 23:08 | Сообщение # 2
Просветленный разум
Сейчас нет на сайте
У меня в движке сделано просто. Ресурс, например текстура, отображается некой функцией. При ее вызове счетчик использования ресурса увеличивается на единицу, в конце кадра этот счетчик сбрасывается. Также имеется переменная, хранящая время последнего обращения к ресурсу. Если счетчик равен 0 и время последнего обращения больше заданного, то ресурс удаляется. эта проверка выполняется по таймеру с заданным интервалом.
Данный функционал делался в расчете под мобильные телефоны и запускается только если заканчивалась память. На практике же на ПК он задействуется редко, в основном при багах с утечкой памяти, ну и помочь ничем не может, так что все это только жрет лишние ресурсы компа.

Цитата (Нохчи)
Кажется, что какие-то очевидные вещи упускаю.

Создай для ресурсов базовый класс. Избавишься от затычек, и сможешь все ресурсы обрабатывать единым массивом.


Windmill 2

WindMill 2D Game Engine
НохчиДата: Воскресенье, 19 Мая 2013, 23:26 | Сообщение # 3
заслуженный участник
Сейчас нет на сайте
Движок сторонний. Поэтому менеджер все-равно должен вертать ресурс известного движку типа.

Многие вопросы по Windows отпадут, если посмотреть тут
ArchidoДата: Понедельник, 20 Мая 2013, 05:51 | Сообщение # 4
Сэнсэй
Сейчас нет на сайте
Цитата (Нохчи)
1)Менеджер хранит внутри себя shared_ptr на ресурс, который возвращается при запросе ресурса(соответственно увеличивается счетчик ссылок). Когда какой-либо объект запросивший ресурс уничтожается, уничтожается и его экземпляр shared_ptr, и счетчик ссылок уменьшается. Соответственно, когда все объекты пользовавшиеся ресурсом будут удалены, счетчик ссылок будет равен 1(shared_ptr из самого менеджера). Если бы можно было заставить объект удаляться при счетчик равному 1, а не 0, было бы прекрасно. Но в нашем случае придется через какие-то промежутки времени вручную вызывать метод сборки мусора и проверять

Тут все дело в том, что менеджер не должен хранить в себе shared_ptr на ресурс, ибо он им ни разу не владеет. Внутри менеджера либо weak (обычно нужен именно он), либо вообще без смартов. Тогда при запросе ресурса возвращается shared_ptr с refcount'ом == 1 и если его никуда не "прикрепить", то он сразу же уничтожается при выходе из области видимости.

Еще имеет смысл сразу же их не удалять, а добавлять в некоторую очередь "на удаление". Обычно менеджеру выдается некий лимит по памяти (довольно большой процент от общего кол-ва памяти на железке) и пока он не превышается - совсем удалять ресурс смысла нет. В добавок всегда существует вероятность, что удаленный ранее ресурс может понадобится снова где-то в дальнейшем (для этого в иделале полезно делить ресурсы на постоянные, возобновляемые и одноразовые. Первые никогда не удаляются, вторые удаляются только когда не хватает памяти, третьи - удаляются сразу же), тогда можно пробегать по этой очереди (лучше, конечно, иметь доп. структуру в виде какого-нибудь binary search tree или хэш таблицы, для быстрого поиска) и если такой ресурс найден - то возвращать ему статус "живого" без особых телодвижений. Ну а когда превышаем лимит, то удаляем с конца очереди N'ное кол-во устаревших ресурсов и создаем необходимый.


C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
НохчиДата: Понедельник, 20 Мая 2013, 08:55 | Сообщение # 5
заслуженный участник
Сейчас нет на сайте
Archido, да, weak бы идеально подошел. Но weak можно создать только и shared_ptr.

UPD
Или имеется ввиду при первом запросе ресурса создать shared_ptr, создать из него weak, сохранить weak и вернуть shared, а при последующих запросах делать weak.lock()?


Многие вопросы по Windows отпадут, если посмотреть тут

Сообщение отредактировал Нохчи - Понедельник, 20 Мая 2013, 09:46
ArchidoДата: Понедельник, 20 Мая 2013, 12:03 | Сообщение # 6
Сэнсэй
Сейчас нет на сайте
Цитата (Нохчи)
Или имеется ввиду при первом запросе ресурса создать shared_ptr, создать из него weak, сохранить weak и вернуть shared, а при последующих запросах делать weak.lock()?

Именно так.


C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
НохчиДата: Понедельник, 20 Мая 2013, 12:09 | Сообщение # 7
заслуженный участник
Сейчас нет на сайте
Archido, спасибо.

Многие вопросы по Windows отпадут, если посмотреть тут
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг