2009-11-06 3 views
11

J'essaie d'écrire un simple gestionnaire de ressources pour le petit jeu de passe-temps que j'écris. L'une des tâches que ce gestionnaire de ressources doit effectuer consiste à décharger les ressources inutilisées. Je peux penser à faire de deux façons:C# - Obtenir le nombre de références à l'objet

  • Lorsqu'un objet ne nécessite plus de référence à la ressource, il doit appeler une méthode du Resource Manager pour signifier qu'il est plus l'utiliser; ou

  • Lorsqu'un objet ne nécessite plus une référence à la ressource, il suffit fixe à null. Ensuite, lorsque le gestionnaire de ressources est invité à décharger ressources inutilisées, il obtient le nombre de références (par réflexion?) De chaque ressource. Si le compte de référence est un (le gestionnaire de ressources va avoir une référence à la ressource), décharger la ressource.

Existe-t-il un moyen d'obtenir la deuxième solution en C#? Merci.

+0

Que fera votre gestionnaire de ressources que le collecteur Garbace ne fait pas? – CannibalSmith

+1

@CannibalSmith - généralement, permettre à plusieurs bits de code de réutiliser la ressource (essentiellement, un cache) –

+0

Son pour le chargement des images, en s'assurant qu'une seule image est chargée à la fois (peu importe le nombre de choses le demandent, seulement une version peut être en mémoire). –

Répondre

11

Il me semble que vous pouvez simplement utiliser WeakReference à partir du gestionnaire de ressources. Le GC fera le reste. Vous aurez besoin de faire un petit casting, mais ce sera simple, et ça marchera.

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) 
} 
+0

Je ferais ceci :) Une chose, cependant: Je peux me tromper, mais je pense que vous devrez peut-être obtenir la bonne référence sur le dictionnaire et vérifier si elle est nulle avant de le retourner. Si vous faites "if (wr.IsAlive) return wr.Target", vous ne prenez jamais une référence forte, donc IsAlive peut renvoyer true, mais au moment où vous renvoyez la valeur, wr.Target peut avoir été collecté. Il existe un autre exemple de code ici: http://msdn.microsoft.com/en-us/library/system.weakreference.aspx –

+1

'object' est assez fort pour empêcher la collecte; Soit il sera nul ou fort. L'appelant devra le transformer pour en faire une référence * typée *, mais c'est un problème différent ... –

+0

.NET 4.5 a une version générique de WeakReference, consultez ceci http://www.philosophicalgeek.com/2014/08/14/prefer-weakreferencet-to-weakreference / – Logerfo

2

Nous avons déjà un gestionnaire de ressources dans .NET, appelé le garbage collector. Une approche très efficace consiste donc à définir les références sur null et à ne rien faire.

Une réponse plus directe: Non, il n'y a aucun moyen d'obtenir les références à un objet.

Vous pouvez étudier le WeakReference class ou utiliser un système de mise en cache.

1

Assurez-vous que le gestionnaire de ressources utilise WeakReference s pour vos ressources. De cette façon, lorsque personne d'autre ne référencera les ressources, elles seront éligibles pour la collecte des ordures.

0

Comme nous l'avons dit par d'autres utilisateurs, ce que vous essayez d'atteindre est déjà fait par le GC, et peut être peaufiné à l'aide d'un WeakReference. Cela implique que dans les environnements gérés tels que .NET, java, etc., cela ne pose aucun problème. Comme l'architecture de framework de bas niveau vous isole de la gestion de la mémoire, si vous avez encore besoin de ce type de fonctionnalité, je vous suggère fortement de revoir votre propre architecture de code, car cela signifierait que vous faites une sorte de mauvaise pratique dans la gestion de la mémoire

28

Couple de choses. Tout d'abord, les objets ne sont pas comptés; les schémas de comptage de référence ont le problème de référence circulaire, par lequel deux objets se réfèrent l'un à l'autre mais sont autrement inaccessibles, et fuient ainsi. .NET utilise une approche mark-and-sweep qui n'utilise pas de compte ref. Deuxièmement, bien que la suggestion d'utiliser une référence faible ne soit pas terrible, ce n'est pas non plus un slam dunk. Vous construisez un cache pour des raisons de performances.(Je suppose que votre recherche minutieuse, empirique et réaliste sur les caractéristiques de performance de votre application a démontré de manière convaincante qu'une stratégie de mise en cache est nécessaire pour atteindre une performance acceptable, si ce n'est pas le cas, vous prenez ces décisions prématurément. le cache doit avoir une POLITIQUE sur le moment où il libère ses ressources, sinon c'est une fuite de mémoire. Comment savez-vous que la politique du gouvernement du Canada et votre politique sont des politiques équivalentes? Le CPG n'a pas été conçu en fonction de vos besoins en matière de performances spécifiques à . C'est-à-dire, il a été conçu pour libérer des ressources qui sont vraiment des ordures, pas pour atteindre un objectif de performance particulier que vous avez en tête. En déléguant la décision au GC, vous abandonnez votre capacité à adapter votre politique de cache à vos besoins de performance.

Questions connexes