• Watching the .NET Garbage Collector

    Here’s an interesting use of SciTech’s .NET Memory Profiler – watching how objects are handled by the .NET CLR garbage collector.

    The sample code create 4 objects – a simple class “Simple”, a class that implements IDisposable “Disposable”, and a class that also implements a destructor “Destructable”.

    .NET Memory Profiler can generate a real-time graph of memory allocations. I’ve instrumented the sample code using SciTech’s API to add comments to the graph so you can match the code execution path against the X axis (time). The object instance count is mapped to the Y axis.

    image

    See how 2 instances of the “Destructable” class existed around the 10 second mark – then one was released at the first GC, then the 2nd (which has the destructor) is only released after the 2nd GC.

    using System; using System.Diagnostics; using SciTech.NetMemProfiler;

    namespace MemoryTesting { internal class Program { private static void Main(string[] args) { MemProfiler.FullSnapShot(“Start”);

            CreateSimple();
    
            CreateDisposable();
            System.Threading.Thread.Sleep(1000);
    
            CreateDestructableAndDispose();
            System.Threading.Thread.Sleep(1000);
    
            CreateDestructable();
            System.Threading.Thread.Sleep(1000);
    
            MemProfiler.AddRealTimeComment("GC");
            GC.Collect();
    
            System.Threading.Thread.Sleep(2000);
            MemProfiler.AddRealTimeComment("WaitForPendingFinalizers");
            GC.WaitForPendingFinalizers();
    
            System.Threading.Thread.Sleep(2000);
    
            MemProfiler.AddRealTimeComment("GC");
            GC.Collect();
    
            System.Threading.Thread.Sleep(1000);
    
            MemProfiler.AddRealTimeComment("End");
            MemProfiler.FullSnapShot();
    
        }
    
        private static void CreateSimple()
        {
            MemProfiler.AddRealTimeComment("Create Simple");
    
            var a = new Simple();
            a.Something += OnEventHandler;
            a.Data = "hey";
    
            a.Something -= OnEventHandler;
    
        }
    
        private static void CreateDisposable()
        {
            MemProfiler.AddRealTimeComment("Create Disposable");
    
            var a = new Disposable();
            a.Something += OnEventHandler;
            a.Data = "ho";
            System.Threading.Thread.Sleep(1000);
            a.Something -= OnEventHandler;
    
            a.Dispose();
        }
    
        private static void CreateDestructableAndDispose()
        {
            MemProfiler.AddRealTimeComment("Create Destructable and Dispose");
    
            var a = new Destructable();
            a.Something += OnEventHandler;
            a.Data = "haha";
            System.Threading.Thread.Sleep(1000);
            a.Something -= OnEventHandler;
    
            a.Dispose();
        }
    
        private static void CreateDestructable()
        {
            MemProfiler.AddRealTimeComment("Create Destructable");
    
            var a = new Destructable();
            a.Something += OnEventHandler;
            a.Data = "haha";
            System.Threading.Thread.Sleep(1000);
            a.Something -= OnEventHandler;
            //a.Dispose();
        }
    
        private static void OnEventHandler(object sender, EventArgs e)
        {
            Debug.WriteLine("Something Fired");
        }
    }
    
    public class Simple
    {
        private string \_data;
    
        public string Data
        {
            get { return \_data; }
            set
            {
                \_data = value;
                OnSomething(null);
            }
        }
    
        public event EventHandler Something;
    
        protected virtual void OnSomething(EventArgs e)
        {
            EventHandler handler = Something;
            if (handler != null) handler(this, e);
        }
    }
    
    public class Disposable : Simple, IDisposable
    {
        #region IDisposable Members
    
        public void Dispose()
        {
            System.Threading.Thread.Sleep(1000);
    
            MemProfiler.AddRealTimeComment("Dispose");
    
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        #endregion
    
        protected virtual void Dispose(bool disposing)
        {
        }
    }
    
    public class Destructable : Disposable
    {
        ~Destructable()
        {
            System.Threading.Thread.Sleep(1000);
    
            MemProfiler.AddRealTimeComment("Destructing");
    
            Dispose(false);
        }
    } }
    

  • Time

    The Byrds were spot on when they sang “To everything… there is a season… and a time to every purpose under heaven”. Spot on, because the lyrics (whilst put to music by Pete Seeger according to Wikipedia) are actually adapted directly from Ecclesiastes 3.

    Particularly appropriate for me at the moment is the line the following line:

    “A right time to plant and another to reap” Ecc 3:2b (The Message)

    r160170_602465[1]Right now in country areas of South Australia, harvest is in full swing. In the past that wouldn’t have meant so much to me, but having worked for the last 18 months at a certain ~Australian~Canadian agribusiness, the change of seasons and especially the impact of weather on crop production has become much more relevant.

    These are interesting, but exciting times. I’m sure a number of the other verses from Ecclesiastes 3 are also applicable at the moment, but I’ll write more about that later!

  • Antihistamines

    I’ve been a long-time hay fever sufferer. I also had a fair bit of allergic conjuctivitis in my younger years which I seem to be growing out of (finally!), though for the last 6 or so years dermographism has been a challenge too. You can just call me “Mr Healthy” :-)

    Because of this, I have developed a more than average interest in antihistamines, and done a bit of research on the various “non-drowsy” over-the-counter products available in Australia.

    The products are grouped by active ingredient, and then ordered by the most familiar brand name with that ingredient. As a rule, the best known brand is usually the most expensive – presumably you’re paying extra for all the marketing and colourful packaging.

    Brand Active Ingredient Size Dose Price Cost per tablet
    Zyrtec Cetirizine 30 10mg 21.95 $ 0.73
    Zodac Cetirizine 30 10mg 9.95 $ 0.33
    Alzene Cetirizine 30 10mg 17.95 $ 0.60
    Telfast Fexofenadine 30 180mg 22.95 $ 0.77
    Xergic Fexofenadine 30 180mg 21.95 $ 0.73
    Fexotabs Fexofenadine 50 180mg 26.45 $ 0.53
    Fexal Fexofenadine 30 180mg 15.95 $ 0.53
    Xyzal Levocetirizine 30 5mg 22.95 $ 0.77
    Clarityne Loratadine 50 10mg 36.95 $ 0.74
    Lorastyne Loratadine 50 10mg 21.95 $ 0.44
    AllerEze Loratadine 50 10mg 27.95 $ 0.56
    Chemists’ Own Loratadine Loratadine 50 10mg 32.95 $ 0.66
    Aerius Desloratadine 28 5mg 24.35 $ 0.87

    Note also, the prices I’ve quoted here are from online pharmacies based in Australia, such as Pharmacy Direct and Pharmacy Online (don’t forget to allow for postage). Buying the same identical product from a non-discount pharmacy may cost up to a 1/3 more.

    I’ve tried all the main kinds, with varying degrees of success. I do think it is a good idea to swap products every few months as in my experience extended use of one specific antihistamine reduced its effectiveness (as though the body became desensitised to it).