none
X509Certificate Perfomance Issue RRS feed

  • Question

  • I'm new to .NET development, but have been a programmer for 16 years, so I'm not new to coding.  I developed this code as a C# COM object (dll) for a lotus notes application.  The COM Object  gets instantiated, and I pass the encoded data to the objects "CertificationData" attribute. It then loops through 4000+ records and calls the "GetCertExpirationDate" method for each record, passing in the "CertificationData" attribute as Bytes.  After some investigating I noticed the X509Certificate object takes 4 seconds to be created.  Everything else including the interop takes milliseconds to complete. I noticed when I first installed the code it ran at warp speed, then degraded over time to the 4 seconds I see now.  I'm worried the object may have a memory leak.  How can I make sure the object is removed, and memory cleared? Deos anybody have example code that would allow me to make sure there are no memory leaks? I've tried a few things that I've commented out.  I've been hitting my head against a stone wall for days.  I'm stuck, and need help!  Heres my code mentioned above: 

    using System;
    using System.IO;
    using System.Security.Cryptography.X509Certificates;
    using System.Text;
    using System.Runtime.InteropServices; //Need for API
    namespace CertificationInfo
    {
        //Certification Class
        public class CertificateInformation
        {
            //Class Attributes
            public string CertificateData; 
            public string ExpirationDate;
            public string NotesUNID;
            public Boolean LoggingOn;
            public String LogFile;
            public Boolean ErrLoggingOn;
            public String ErrFile;
            private MemoryManagement MemMngr;
            private DLLLog Logging;
            private String DateString;
                    
            //Constructor
            public CertificateInformation()
            {
                //Reset Expiration Date
                this.ExpirationDate = "";
                this.LoggingOn = false;
                this.ErrLoggingOn = false;
                DateTime TodaysDate = DateTime.Today;
                this.DateString = (TodaysDate.Year.ToString())+(TodaysDate.Month.ToString())+(TodaysDate.Day.ToString());
                this.LogFile = "DLLLog"+this.DateString+".txt";
                this.ErrFile = "DLLErrors"+this.DateString+".txt";
                this.MemMngr = new MemoryManagement();
                this.Logging=new DLLLog();
            }
            //Method
            public string GetCertExpirationDate(string rawdata)
            {
                try
                {
                    this.Logging.LogMe(this.LogFile, "Start Logging - UNID: "+this.NotesUNID,this.LoggingOn);
                    //Clean Up Memory
                    //this.MemMngr.ReleaseMemory();
                    //Reset Expiration Date Property
                    this.ExpirationDate = "";
                    //Check for data
                    if (rawdata == "" && this.CertificateData == "")
                    {
                        this.Logging.LogMe(this.LogFile, "Variables rawdata and certificatedata blank!", this.LoggingOn);
                        //Nothing is passed & property is blank
                        this.ExpirationDate = "";
                    }
                    else
                    {
                        //Check for Raw Data value
                        if (rawdata != "")
                        {
                            this.Logging.LogMe(this.LogFile, "Using variable rawdata!", this.LoggingOn);
                            this.CertificateData = rawdata;
                        }
                    
                        //Convert Property Array
                        //Might be best to use unicode Under Encoding namespace
                        //System.Text.UnicodeEncoding Encoding=new System.Text.UnicodeEncoding();
                        //Byte[] bytedata=Encoding.GetBytes(this.CertificateData);
                        this.Logging.LogMe(this.LogFile, "Converting Cert Data: " + this.CertificateData, this.LoggingOn);
                        //Convert Property to byte array
                        System.Text.ASCIIEncoding Encoding = new System.Text.ASCIIEncoding();
                        Byte[] bytedata = Encoding.GetBytes(this.CertificateData);
                        this.Logging.LogMe(this.LogFile, "Cert Data Converted!", this.LoggingOn);
                        //Create Encoding Object
                        this.Logging.LogMe(this.LogFile, "Creating X509 Object...", this.LoggingOn);
                        X509Certificate CertificateObject = new X509Certificate(bytedata);
                        //X509Certificate2 CertificateObject = new X509Certificate2(bytedata);
                        //this.CertificateObject = new X509Certificate(bytedata);
                        this.Logging.LogMe(this.LogFile, "X509 Object Created!", this.LoggingOn);
                        
                        //Might have to check to see iff cert object is null though catch should pick it up 
                        //Get Expiration date
                        //this.ExpirationDate = CertificateObject.GetExpirationDateString();
                        this.Logging.LogMe(this.LogFile, "Get expirationdate...", this.LoggingOn);
                        this.ExpirationDate = CertificateObject.GetExpirationDateString();
                        this.Logging.LogMe(this.LogFile, "Expiration Date: " + this.ExpirationDate, this.LoggingOn);
                        //Reset Object & Certificate Data Property
                        //this.Logging.LogMe("DLLLog", "Nulling Out Objects!");
                        //CertificateObject = null;
                        //Encoding = null;
                        //this.Logging.LogMe("DLLLog", "Resetting Certificate...");
                        //CertificateObject.Reset();
                        //this.CertificateData = "";
                        //Clean Up Memory
                        //this.Logging.LogMe("DLLLog", "Memory Manager Clean-up!");
                        //this.MemMngr.ReleaseMemory();
                    }
                }
                //Error Trapping in case of error still returns something
                catch
                {
                    this.Logging.LogMe(this.ErrFile, "Start Error Logged - UNID: " + this.NotesUNID, this.ErrLoggingOn);
                    this.Logging.LogMe(this.ErrFile, "Error Data -: " + this.CertificateData, this.ErrLoggingOn);
                    this.Logging.LogMe(this.ErrFile, "End Error Logged - UNID: " + this.NotesUNID, this.ErrLoggingOn);
                    this.ExpirationDate = "";
                }
               
                //this.Logging.LogMe("DLLLog", "Returning expiration date!");
                this.Logging.LogMe(this.LogFile, "End Logging - UNID: " + this.NotesUNID + " Returning expiration date!", this.LoggingOn);
                return this.ExpirationDate;
            }
        }
        
        //Debug Log Code
        public class DLLLog
        {
            //Constructor
            public DLLLog()
            {
                
            }
            //Methods
            public void LogMe(String Filename,String LogMeMessage,Boolean LogOn)
            {
                if (LogOn==true)
                {
                    using (StreamWriter w = File.AppendText(Filename))
                    {
                        WriteLog(LogMeMessage, w);
                    }
                }
            }
            public static void WriteLog(string logMessage,TextWriter w)
            {
                w.Write("\r\nLog Entry: ");
                w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString());
                //w.WriteLine("  :");
                w.WriteLine("  :{0}", logMessage);
                w.WriteLine("-------------------------------");
            }
            public static void ReadLog(StreamReader r)
            {
                string line;
                while ((line = r.ReadLine()) != null)
                {
                    Console.WriteLine(line);
                }
            }
        }
        //API Class to Clean up Memory threads
        public class MemoryManagement
        {
            //Memory Management API
            [DllImport("kernel32.dll")]
            public static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max);
            //Method
            public void ReleaseMemory()
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                {
                    SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
                }
            }
        }
    }

     

    Friday, February 7, 2014 6:36 PM

All replies

  • Hello,

    >>How can I make sure the object is removed, and memory cleared?

    Have a try to use using block, it will provide a convenient syntax that ensures the correct use of IDisposable objects.

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, February 10, 2014 9:08 AM
    Moderator
  • I tried to use a using block, but VS tells me that the X509Certificate object does not implement the System.IDisposable method.  Unless I'm reading it wrong or not typing in the using statement correctly.

    using (X509Certificate CertificateObject = new X509Certificate(bytedata))
                        {
                            //add some code here
                        }

    "System.Security.Cryptography.X509Certificates.X509Certificate: type used in using statement must be implicity convertibles to System.IDisposable"

    Since "using" is similar to using a "finally" block, I thought about using that in my try catch statements. I'm just not sure how to truly remove the object so GC will pick it up. 

    I'm open to any other suggestions? 



    • Edited by UltBizzarro Monday, February 10, 2014 12:41 PM
    Monday, February 10, 2014 12:39 PM
  • I added a finally block and changed the object to a property.  According to Microsoft the X509Certificate.Reset() method should clear it out of memory so I created the finally block.  Still takes a while (4 seconds) to create the object, but I hope this would solve any possible memory leaks.  Does anyone see an issue with the code that could cause the slowness or a memory leak issue?

    Here is my revised code:

    using System;
    using System.IO;
    using System.Security.Cryptography.X509Certificates;
    using System.Text;
    using System.Runtime.InteropServices; //Need for API
    namespace CertificationInfo
    {
        //Certification Class
        public class CertificateInformation
        {
            //Class Attributes
            public string CertificateData; 
            public string ExpirationDate;
            public string NotesUNID;
            public Boolean LoggingOn;
            public String LogFile;
            public Boolean ErrLoggingOn;
            public String ErrFile;
            private X509Certificate CertificateObject;
            private MemoryManagement MemMngr;
            private DLLLog Logging;
            private String DateString;
                    
            //Constructor
            public CertificateInformation()
            {
                //Reset Expiration Date
                this.ExpirationDate = "";
                this.LoggingOn = false;
                this.ErrLoggingOn = false;
                DateTime TodaysDate = DateTime.Today;
                this.DateString = (TodaysDate.Year.ToString())+(TodaysDate.Month.ToString())+(TodaysDate.Day.ToString());
                this.LogFile = "DLLLog"+this.DateString+".txt";
                this.ErrFile = "DLLErrors"+this.DateString+".txt";
                this.MemMngr = new MemoryManagement();
                this.Logging=new DLLLog();
            }
            //Method
            public string GetCertExpirationDate(string rawdata)
            {
                try
                {
                    this.Logging.LogMe(this.LogFile, "Start Logging - UNID: " + this.NotesUNID, this.LoggingOn);
                    //Clean Up Memory
                    //this.MemMngr.ReleaseMemory();
                    //Reset Expiration Date Property
                    this.ExpirationDate = "";
                    //Check for data
                    if (rawdata == "" && this.CertificateData == "")
                    {
                        this.Logging.LogMe(this.LogFile, "Variables rawdata and certificatedata blank!", this.LoggingOn);
                        //Nothing is passed & property is blank
                        this.ExpirationDate = "";
                    }
                    else
                    {
                        //Check for Raw Data value
                        if (rawdata != "")
                        {
                            this.Logging.LogMe(this.LogFile, "Using variable rawdata!", this.LoggingOn);
                            this.CertificateData = rawdata;
                        }
                        //Convert Property Array
                        //Might be best to use unicode Under Encoding namespace
                        //System.Text.UnicodeEncoding Encoding=new System.Text.UnicodeEncoding();
                        //Byte[] bytedata=Encoding.GetBytes(this.CertificateData);
                        this.Logging.LogMe(this.LogFile, "Converting Cert Data: " + this.CertificateData, this.LoggingOn);
                        //Convert Property to byte array
                        System.Text.ASCIIEncoding Encoding = new System.Text.ASCIIEncoding();
                        Byte[] bytedata = Encoding.GetBytes(this.CertificateData);
                        this.Logging.LogMe(this.LogFile, "Cert Data Converted!", this.LoggingOn);
                        //Create Encoding Object
                        this.Logging.LogMe(this.LogFile, "Creating X509 Object...", this.LoggingOn);
                        //X509Certificate CertificateObject = new X509Certificate(bytedata);
                        this.CertificateObject = new X509Certificate(bytedata);
                        //X509Certificate2 CertificateObject = new X509Certificate2(bytedata);
                        //this.CertificateObject = new X509Certificate(bytedata);
                        this.Logging.LogMe(this.LogFile, "X509 Object Created!", this.LoggingOn);
                        //Might have to check to see iff cert object is null though catch should pick it up 
                        //Get Expiration date
                        //this.ExpirationDate = CertificateObject.GetExpirationDateString();
                        this.Logging.LogMe(this.LogFile, "Get expirationdate...", this.LoggingOn);
                        this.ExpirationDate = this.CertificateObject.GetExpirationDateString();
                        this.Logging.LogMe(this.LogFile, "Expiration Date: " + this.ExpirationDate, this.LoggingOn);
                        //Reset Object & Certificate Data Property
                        //this.Logging.LogMe("DLLLog", "Nulling Out Objects!");
                        //CertificateObject = null;
                        //Encoding = null;
                        //this.Logging.LogMe("DLLLog", "Resetting Certificate...");
                        //CertificateObject.Reset();
                        //this.CertificateData = "";
                        //Clean Up Memory
                        //this.Logging.LogMe("DLLLog", "Memory Manager Clean-up!");
                        //this.MemMngr.ReleaseMemory();
                        //Moving Return for finally block
                        //this.Logging.LogMe(this.LogFile, "End Logging - UNID: " + this.NotesUNID + " Returning expiration date!", this.LoggingOn);
                        //return this.ExpirationDate;
                    }
                }
                //Error Trapping in case of error still returns something
                catch
                {
                    this.Logging.LogMe(this.ErrFile, "Start Error Logged - UNID: " + this.NotesUNID, this.ErrLoggingOn);
                    this.Logging.LogMe(this.ErrFile, "Error Data -: " + this.CertificateData, this.ErrLoggingOn);
                    this.Logging.LogMe(this.ErrFile, "End Error Logged - UNID: " + this.NotesUNID, this.ErrLoggingOn);
                    this.ExpirationDate = "";
                    //this.Logging.LogMe(this.LogFile, "End Logging - UNID: " + this.NotesUNID + " Returning expiration date!", this.LoggingOn);
                    //return this.ExpirationDate;
                }
                finally
                {
                    this.Logging.LogMe(this.LogFile, "Finally block entered!", this.LoggingOn);
                    this.CertificateObject.Reset();
                }
               
                //this.Logging.LogMe("DLLLog", "Returning expiration date!");
                this.Logging.LogMe(this.LogFile, "End Logging - UNID: " + this.NotesUNID + " Returning expiration date!", this.LoggingOn);
                return this.ExpirationDate;
            }
        }
        
        //Debug Log Code
        public class DLLLog
        {
            //Constructor
            public DLLLog()
            {
                
            }
            //Methods
            public void LogMe(String Filename,String LogMeMessage,Boolean LogOn)
            {
                if (LogOn==true)
                {
                    using (StreamWriter w = File.AppendText(Filename))
                    {
                        WriteLog(LogMeMessage, w);
                    }
                }
            }
            public static void WriteLog(string logMessage,TextWriter w)
            {
                w.Write("\r\nLog Entry: ");
                w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString());
                //w.WriteLine("  :");
                w.WriteLine("  :{0}", logMessage);
                w.WriteLine("-------------------------------");
            }
            public static void ReadLog(StreamReader r)
            {
                string line;
                while ((line = r.ReadLine()) != null)
                {
                    Console.WriteLine(line);
                }
            }
        }
        //API Class to Clean up Memory threads
        public class MemoryManagement
        {
            //Memory Management API
            [DllImport("kernel32.dll")]
            public static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max);
            //Method
            public void ReleaseMemory()
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                {
                    SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
                }
            }
        }
    }


    • Edited by UltBizzarro Monday, February 10, 2014 2:42 PM
    Monday, February 10, 2014 2:39 PM
  • Hello,

    Have a try to use x509certificate2 to check whether it will perform better.

    Regards.

    Wednesday, February 12, 2014 8:09 AM
  • I think I have created as an X509Certificate2 with no improvement.  Definitley has something to do with creating that object.  Thought I read somewhere it's really an API C++ wrapper behind the scenes, which may cause some of the issue.  Read so much about it, and nobody seems to have an answer.  Has anybody else seen slowness with looping through, and creating an X509Certificate object?
    Thursday, February 20, 2014 4:21 PM