3

I have a collection (I'm writing a Weak Dictionary) and I need to cull the dead WeakReferences periodically. What I've usually seen is checks in the Add and Remove methods that say, "After X modifications to the collection, it's time to cull." This will be acceptable for me, but it seems like there should be a better way.

I would really like to know when the GC ran and run my cleanup code immediately after. After all, the GC is probably the best mechanism for determining when is a good time to clean up dead references. I found Garbage Collection Notifications, but it doesn't look like this is what I want. I don't want to spawn a separate thread just to monitor the GC. Ideally, my collection would implement IWantToRunCodeDuringGC or subscribe to a System.GC.Collected event. But the .NET framework probably can't trust user code to run during a GC...

Or maybe there's another approach I'm overlooking.

EDIT: I don't think it matters if my code runs after, before, or during the GC.

Community
  • 1
  • 1
default.kramer
  • 5,943
  • 2
  • 32
  • 50
  • 1
    The first time you run into a WeakReference that has its IsAlive property set to false would be a good time. That's a sure-fire sign that a garbage collection has taken place. – Hans Passant Apr 23 '11 at 14:24

3 Answers3

2

I guess you want to create a weak dictionary as a way of “lazy” caching of some data.

You need to consider the fact that GC will occur very often and your weak references will be dead most of the time if no other objects will reference them. GC occurs approximately after every 256KB of memory is allocated. It is pretty often.

You probably will be better by implementing your cache as a dictionary with a maximum number of elements. Then you can use least-recently used algorithm or time-based algorithm for pushing elements out of the collection. Usually such approach has better performance and memory consumption than using weak references.

Dennis
  • 2,615
  • 2
  • 19
  • 20
  • It's not going to be used as a cache; it's more a way of attaching data to a given object. Two clients of the dictionary, when providing the same key, **must** get the same instance out. – default.kramer Apr 23 '11 at 15:01
  • 1
    Could you elaborate a little bit more on the nature of your keys? What are they? Some kinds of IDs or full-fledged objects with which your values associated? You could probably use System.Runtime.CompilerServices. ConditionalWeakTable if it is association scenario. – Dennis Apr 23 '11 at 15:10
  • This looks like exactly what I want. I am attaching a ValidationModel to an arbitrary Viewmodel, so both are full-fledged objects. I don't control the type of the Viewmodel. – default.kramer Apr 23 '11 at 15:17
1

Can't you just use an object with no references, then call some code in the finalizer? The finalizer is called when the GC is collecting the object.

EDIT: Then of course, you wouldn't know when the GC was done.. Hmm.

jakobbotsch
  • 6,167
  • 4
  • 26
  • 39
  • That actually might work! I thought of finalizers, but my Weak Dictionary won't be getting finalized. But if I create a sacrificial object that I know will get GC'd... I'll give this a try! (I don't really care if the code runs after, before, or during the GC) – default.kramer Apr 23 '11 at 14:19
0

From the standpoint of avoiding memory leaks, I would suggest that when something is added to a dictionary, you check whether the number of garbage-collections that have been performed. If the number of items that have been added between the last time the dictionary was checked and the time the last collection occurred exceeds a reasonable fraction of the size of the dictionary (say, 10%, or some minimum number of items, whichever is less), that would be a sign that the dictionary should be swept. Note that this approach will limit the number of excessive items in the dictionary to a certain fraction of the dictionary size while offering reasonable performance regardless of dictionary size.

supercat
  • 77,689
  • 9
  • 166
  • 211