none
Multi-cpu GC does not collect certs RRS feed

  • General discussion

  • The code at the end demonstrates a problem with GC and certificates on multi-cpu machines.

    The code has three run types:
    - Cert. Creates a cert on the stack.
    - Memory.  Creates a memory block on the stack.
    - CertWithGc. Creates a cert on the stack and explicitly calls the GC.

    Memory usage was monitored via Task Manager

    Results of running - Single CPU/Dual Core, Net 2.0/3.5, XP, Vista
    - Cert, steady state memory usage successful exit
    - Memory, steady state memory usage successful exit
    - CertWithGc, steady state memory usage successful exit

    Results of running - Dual CPU/(Dual Core and Quad Core), Net 2.0/3.5, XP, Windows Server 2003
    - Cert, gradual usage of memory until Out Of Memory exception occurs.
    - Memory, steady state memory usage successful exit
    - CertWithGc, steady state memory usage successful exit

    In the above steady state means that the memory reached a certain level and then stayed there.

    I would expect that the out of memory error should not occur.  Or I would like an explanation why it is correct.



        using System;  
        using System.Threading;  
        using System.Security.Cryptography.X509Certificates;  
     
        namespace TestCertVmBug  
        {  
        class Program  
        {  
            private static int attempts;  
            private static bool isError;  
            private static byte[] certBytes;  
     
            private static readonly Object lockObject = new Object();  
            private static int objectCnt;  
            private static int maxObjectCnt;  
     
            private enum RunType  
            {  
                Cert,        // Fails  
                Memory,      // Ok  
                CertWithGc,  // Ok  
            };  
            private static RunType runType;  
     
            static void Main(string[] args)  
            {  
                try  
                    {  
                    runType = SetRunType(args);  
                    System.Console.WriteLine("RunType=" + runType);  
                    Test();  
                    }  
                catch(Exception e)  
                    {  
                    System.Console.WriteLine("Exception " + e);  
                    }  
            }  
     
            private static RunType SetRunType(string[] args)  
            {  
                if ((args == null) || (args.Length == 0))  
                    return RunType.Cert;  
     
                if ("Cert".Equals(args[0]))  
                    return RunType.Cert;  
                if ("Memory".Equals(args[0]))  
                    return RunType.Memory;  
                if ("CertWithGc".Equals(args[0]))  
                    return RunType.CertWithGc;  
     
                throw new Exception("Illegal command line option=" + args[0]);  
     
            }  
     
            private static void Test()  
            {  
                // Grab memory so it takes less time to fail.  
                byte[] reserveMemory = new byte[1000 * 1024 * 1024];  
     
     
                certBytes = Convert.FromBase64String(base64Cert);  
     
                attempts = 8000;  
                const int cnt = 400;  
     
                objectCnt = 0;  
                maxObjectCnt = 100000;  
     
                isError = false;  
     
                Thread[] threads = new Thread[cnt];  
                for (int i=0; i < cnt; i++)  
                    threads[i] = new Thread(new ThreadStart(Run));  
     
                for (int i=0; i < cnt; i++)  
                    threads[i].Start();  
            }  
     
            private static void Run()  
            {  
                try  
                    {  
                    Thread.Sleep(0);  
                    for (int i = 0; (i < attempts) && !isError; i++)  
                        {  
                        if (runType == RunType.Memory)  
                            {  
                            // This line causes a steady state at the maximum  
                            byte[] b = new byte[32 * 1024];  
                            }  
                        else  
                            {  
                            // The following line will just keep going up and   
                            // eventually run out of memory.unless GC is  
                            // explicitly called.  
                            X509Certificate2 c = new X509Certificate2(certBytes);  
                            }  
     
     
                        ++objectCnt;  
     
                        if ((runType == RunType.CertWithGc) && (objectCnt > maxObjectCnt))  
                            {  
                            lock(lockObject)  
                                {  
                                if (objectCnt > maxObjectCnt)  
                                    {  
                                    //  
                                    // BIZARRE!!  
                                    //  
                                    //     GC.Collect() does not fix the problem  
                                    //  
                                    //     GC.GetTotalMemory(true) does.  
                                    //  
                                    GC.GetTotalMemory(true);  
                                    //GC.Collect();  
                                    objectCnt = 0;  
                                    }  
                                }  
                            }  
                        }  
                    }  
                catch(Exception e)  
                    {  
                    isError = true;  
                    System.Console.WriteLine("Thread Exception " + e.Message);  
                    }  
            }  
     
            const String base64Cert = "" 
                    + "MIICdzCCAeCgAwIBAgIQBlqxk8OAUKZBwt7R6Qjn0TANBgkqhkiG9w0BAQQFADA/MT0wOwYDVQQDEzRF"  
                    + "QUFCRUFBQi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vd0E9MB4XDTA2MDky"  
                    + "ODIzMTA1MFoXDTM5MTIzMTIzNTk1OVowPzE9MDsGA1UEAxM0RUFBQkVBQUIvLy8vLy8vLy8vLy8vLy8v"  
                    + "Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL3dBPTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAruHW"  
                    + "/hnpwXVqqZGZbl9Yww553iKVq8NstrVO3PzToxuR6Qhz+R60Pc2x50DZJA25r0y9Up2uHINsddtMzOLL"  
                    + "AMLZdLRBTeKlDEJirxbRu8jREkFAy52ZUmGRpC6m69nCSoBpUoes3PlNMIUYOSiVB9bEabqZ7MV1x2y2"  
                    + "N9+G5y0CAwEAAaN0MHIwcAYDVR0BBGkwZ4AQ3+VJODx+M/B+IZANzguXbaFBMD8xPTA7BgNVBAMTNEVB"  
                    + "QUJFQUFCLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy93QT2CEAZasZPDgFCm"  
                    + "QcLe0ekI59EwDQYJKoZIhvcNAQEEBQADgYEAXvcsLAeLuz8mnfGHE9RS+bQIxpuIEBNIkJr8hMPSvFzY"  
                    + "KZ5mPz5MvDP9OMrloQLueF+lFn7SduGbpC4nKIMdW54Ae1hvqw07GfbvPdma1+rfB0rBbvokJkRoC7O2"  
                    + "T5kvxJ5S8MRD9Rf367AiIr2Qis2MwTsE5lXu9edHzPh1iTA="  
                    ;  
     
        }  
        }  
     
    • Changed type Zhi-Xin Ye Tuesday, October 7, 2008 12:31 PM change to comment since no respnse for more than 3 days
    • Changed type Zhi-Xin Ye Tuesday, October 7, 2008 12:31 PM change to comment since no respnse for more than 3 days
    Tuesday, September 30, 2008 4:47 PM

All replies

  • What does this code actually do ???

    greet
    Microsoft Certified Application Developer (MCAD), M.Sc. in Astrophysics
    Friday, October 3, 2008 11:34 AM
  • Dragoslav Zaric said:

    What does this code actually do ??? 


     It demonstrates the problem described which is an out of memory exception.
    Friday, October 10, 2008 3:12 PM