Are there any events that tell an application when

2019-04-09 15:39发布

问题:

I am trying to find a way to know about garbage collection. Either, when it has started, finished or is in process. I really just need some event connected to the collection itself (I think).

My issue is that I have a WeakEventManager (written from scratch) and I have cleanup methods that delete and WeakReferences that are no longer alive (WeakReferences are in a Dictionary).

The issue is that I have to know when it is time to "clean up". It would be nice to cleanup when the collector is doing its thing. Even if it is after the garbage collection, at least the next collection will remove these old objects.

回答1:

Here's the class I used to log to SmartInspect that GC has occured. You should easily be able to change what this class does.

To get it started, simply call GCLog.Register();.

#region File Header
// This file Copyright © 2007 Lasse Vågsæther Karlsen, All rights reserved.
//
// $Id: GCLog.cs 135 2008-05-28 11:28:37Z lassevk $
#endregion

#region Using

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Gurock.SmartInspect;

#endregion

namespace PresentationMode
{
    /// <summary>
    /// This class is used to get a running log of the number of garbage collections that occur,
    /// when running with logging.
    /// </summary>
    public sealed class GCLog
    {
        #region Construction & Destruction

        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="GCLog"/> is reclaimed by garbage collection.
        /// </summary>
        ~GCLog()
        {
            SiAuto.Main.LogMessage("GARBAGE COLLECTED");
            if (!AppDomain.CurrentDomain.IsFinalizingForUnload() && !Environment.HasShutdownStarted)
                new GCLog();
        }

        #endregion

        #region Public Static Methods

        /// <summary>
        /// Registers this instance.
        /// </summary>
        public static void Register()
        {
#if DEBUG
            if (SiAuto.Si.Enabled)
                new GCLog();
#endif
        }

        #endregion
    }
}


回答2:

You could monitor the .NET Memory performance counter object. There are counts for number of gen 0, 1, and 2 collections.

Generally on a GC based system, directly referencing the GC is something of an anti-pattern. You would likely (given the limited description) be better just lazily cleaning up when you try and used a cleared WeakReference.



回答3:

The System.GC class offers a RegisterForFullGCNotification method which will allow notifications to be raised when garbage collection is about to be done, and when it's been completed.

It's not ideal, as there are a few caveats to using this method, such as concurrent garbage collection must be disabled for this method to work.

Please see the following links for full info:

Garbage Collection Notifications

GC.RegisterForFullGCNotification Method



回答4:

If you create a throw-away object that has an outgoing reference to your objects but no incoming references, ie

new MyGcMonitor(this);  // don't store result

And if you make sure that MyGcMonitor has a Finalizer (destructor) then that finalizer will be called after the GC fase is completed, on a separate thread. The finalizer can call a method tho tell your class finalization is complete.

The tricky part is if you need it again, for instance if you decide not to free your object. You then have to setup a sequence that, outside of the running GC thread, creates another instance of MyGcMonitor. I suppose you could use delegate.invoke and in that delegate first call GC.WaitForPendingFinalizers().

Resurrecting the MyGcMonitor would have a similar problem of removing the (static) reference later on.



回答5:

In a thread with low priority you can check if the application needs cleaning with this simple static method.

    private static bool NeedsCleaning ()
    {
        if (DummyRef.IsAlive) {
            return false;
        }
        DummyRef = new WeakReference (new object ());
        return true;
    }