Events (Multicast delegates), Cache, and Garbage Collection

One issue that has perplexed me since having a nasty bug associated with a static event declared in a cached object is:  If you cache an object, how can your ASP.NET pages that subscribe to its events be garbage collected when that cached object has a delegate with references to event handling methods in the page object?

Some background on my issue:  I had declared a static Login event in a User object so I could be notified globally when a user logged in.  Every page subscribed to this static event.  Of course we know that only one static event exists for the app domain even though many objects of that type may exists.  So we have one static multicast delegate containing references to event-handling methods in every single page object in my web app.  Well, from examing the perf counters, memory keeping being consumed but never freed.  Why isn’t the garbage collector freeing these page objects?  Allocation Profiler reveals a whole bunch of Page objects in the Heap.  It turns out that as long as this static delegate has a reference to a method in the page object, that page object is not available for garbage collection.

Why, then, doesn’t ASP.NET exibit the same behavior when you have an instance event in an object that is cached and lives for the life of the appdomain?  This same object retains references to the event-handling methods in the pages, but the garbage collector reclaims their memory.  Why this difference in behavior?  I keep searching.