С# - Получить количество ссылок на объект

Я пытаюсь написать простой менеджер ресурсов для маленькой хобби, которую я пишу. Одной из задач, которые должен выполнять этот менеджер ресурсов, является выгрузка неиспользуемых ресурсов. Я могу думать об этом двумя способами:

  • Когда объект больше не требует ссылку на ресурс, он должен вызвать метод диспетчера ресурсов означает, что он больше не использует его; или

  • Когда объект больше не требует ссылку на ресурс, это просто устанавливает значение null. Затем, когда Менеджер ресурсов попросят выгрузить неиспользуемых ресурсов, он получает счетчик ссылок (через отражение?) каждый ресурс. Если счетчик ссылок является одним (диспетчер ресурсов иметь ссылку на ресурс), выгрузите ресурс.

Есть ли способ получить второе решение в С#? Спасибо.

Ответ 1

Мне кажется, что вы можете просто использовать WeakReference в диспетчере ресурсов. GC сделает все остальное. Вам нужно сделать небольшое кастинг, но это будет просто и будет работать.

class Manager {
    Dictionary<string, WeakReference> refs =
        new Dictionary<string, WeakReference>();
    public object this[string key] {
        get {
            WeakReference wr;
            if (refs.TryGetValue(key, out wr)) {
                if(wr.IsAlive) return wr.Target;
                refs.Remove(key);
            }
            return null;
        }
        set {
            refs[key] = new WeakReference(value);
        }
    }
}
static void Main() {
    Manager mgr = new Manager();
    var obj = new byte[1024];
    mgr["abc"] = obj;

    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
    Console.WriteLine(mgr["abc"] != null); // true (still ref'd by "obj")

    obj = null;
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
    Console.WriteLine(mgr["abc"] != null); // false (no remaining refs)
}

Ответ 2

Пара вещей. Во-первых, объекты не подсчитываются; схемы подсчета ссылок имеют круглую справочную проблему, в которой два объекта ссылаются друг на друга, но в противном случае недоступны и, следовательно, течет..NET использует подход mark-and-sweep, который не использует значения ref.

Во-вторых, хотя предложение использовать слабую ссылку не страшно, это тоже не хлопок. Вы создаете кеш по соображениям производительности. (Я полагаю, что ваше тщательное, эмпирическое, реалистичное исследование характеристик производительности вашего приложения убедительно продемонстрировало, что стратегия кэширования необходима для достижения приемлемой производительности, если это не так, то вы принимаете эти решения преждевременно.) Каждый кэш должен иметь ПОЛИТИКУ, когда он освобождает свои ресурсы, в противном случае это утечка памяти.

Откуда вы знаете, что политика GC и ваша политика являются эквивалентными политиками? GC не был разработан с учетом ваших конкретных потребностей в производительности. То есть, он был разработан для выпуска ресурсов, которые действительно являются мусором, а не для достижения какой-либо конкретной цели производительности, о которой вы имели в виду. Делегируя решение GC, вы отказываетесь от своей способности настраивать политику кэша в соответствии с вашими потребностями в производительности.

Ответ 3

У нас уже есть менеджер ресурсов в .NET, называемый сборщиком мусора. Поэтому очень эффективный подход - установить ссылки на нуль и ничего не делать.

Более прямой ответ: Нет, нет способа получить ссылки на объекта.

Возможно, вам захочется изучить класс WeakReference или использовать систему кэширования.

Ответ 4

Убедитесь, что менеджер ресурсов использует WeakReference для ваших ресурсов. Таким образом, когда никто не ссылается на ресурсы, они будут иметь право на сбор мусора.

Ответ 5

Как уже говорили другие пользователи, то, что вы пытаетесь достичь, уже сделано GC и может быть точно настроено с помощью WeakReference.

Это означает, что в управляемых средах, таких как .NET, java и т.д., это не проблема.

Поскольку низкоуровневая структура инфраструктуры изолирует вас от управления памятью, если вам все еще нужна такая функциональность, я настоятельно рекомендую вам просмотреть свою собственную архитектуру кода, потому что это будет означать, что вы делаете что-то плохое -practise в управлении памятью