2

I am getting an out of memory exception when using a time. Could it have something to do with using the timer in a struct - Is it possible to have a timer in a struct such as below:

 public struct SessionStruct 
{
    private bool _isElapsed;
    public bool isElapsed
    {
        get{return _isElapsed;}
        set { _isElapsed = value; }
    }
    public string sessionID
    {
        get;
        set;
    }
    public DateTime time
    {
        get;
        set;
    }

    public Timer timer
    { get; set; }

};

This is the elapsed event handler:

static void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        req = "<Request><ID>1234567</ID><type>10</type><attribute>" + session1.sessionID + "|</attribute></Request>";}

[EDIT]

Here is the code for the instantiating and setting values - this is only part of it...

        public Request(string request, Database db)
    {

//instantation s = new SessionStruct(); s.timer = new Timer(60000); s.timer.Enabled = true; //db = new Database(); try { Debug.WriteLine("Started a new request"); doc = new XmlDocument(); doc.LoadXml(request); string attribute = ""; //string sessionID = ""; ArrayList attributeArray = new ArrayList(); ArrayList queryArray = new ArrayList();

            int iteration = 0;

            bool hasSpecial = false ;
        nodelist = doc.SelectNodes("/Request");
        foreach (XmlNode xn in nodelist)
        {
            try
            {
                type = xn["type"].InnerText;
                id = xn["ID"].InnerText;
                attribute = xn["attribute"].InnerText;
                Debug.WriteLine("Processing Request of type: " + type + "\nWith Id number: " + id + "\nWith attribute string: " + attribute);
                for (int i = attribute.IndexOf('|'); i != -1; )
                {
                    attributeArray.Add(attribute.Substring(0, i));
                    if (attribute.Substring(0, i).Contains('\''))
                        hasSpecial = true;
                    attribute = attribute.Substring(i + 1);

                    i = attribute.IndexOf('|');
                }

//setting variables if (type == "1" && attributeArray.Count != 2) { s.sessionID = attributeArray[0].ToString(); s.time = DateTime.Now; s.timer.Start(); isNotLogin = true; attributeArray.RemoveAt(0); } else if (type != "1") { s.sessionID = attributeArray[0].ToString(); s.time = DateTime.Now; s.timer.Start(); isNotLogin = true; attributeArray.RemoveAt(0); }

I return the struct here

 public SessionStruct getSessionStruct()
    {
            return s; 
    }

It is returned to another class like:

                        sessStruct2 = iRequest.getSessionStruct();
                        int x;
                        for(x = 0; x< session.Count; x++)
                        {
                            sessStruct = (SessionStruct)session[x];


                            if (sessStruct.sessionID == sessStruct2.sessionID)
                            {
                                Debug.WriteLine("Resetting Session Timer");
                                session.RemoveAt(x);
                                sessStruct2.timer.Stop(); //resetting timer
                                sessStruct2.timer.Start();
                                Debug.WriteLine("Session Timer Reset SUCCESSFUL");
                                session.Add((object)sessStruct2);
                                Debug.WriteLine("Added Session        "+sessStruct2.sessionID+" Successfully to sessions table");
                                guiServer.log("Added Session " + sessStruct2.sessionID + " Successfully to sessions table");
                                break;
                            }

                       }

                        if(x==session.Count)
                        {
                                session.Add(iRequest.getSessionStruct());
                                Debug.WriteLine("Added the session");
                        }

And I created a thread that checks to see whether the timer is elapsed like this

while (true)
            {
                if (session.Count > 0)
                {

                    session1 = (SessionStruct)session[0];
                    session1.timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed)

                }
            }

And here is the stack trace:

 first chance exception of type 'System.OutOfMemoryException' occurred in mscorlib.dll

System.Transactions Critical: 0 : http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/UnhandledUnhandled exceptionVNurseService.exeSystem.OutOfMemoryException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Exception of type 'System.OutOfMemoryException' was thrown. at System.MulticastDelegate.CombineImpl(Delegate follow) at System.Timers.Timer.add_Elapsed(ElapsedEventHandler value) at VNurseService.Server.Session.checkSessionList() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown. at System.MulticastDelegate.CombineImpl(Delegate follow) at System.Timers.Timer.add_Elapsed(ElapsedEventHandler value) at VNurseService.Server.Session.checkSessionList() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() An unhandled exception of type 'System.OutOfMemoryException' occurred in mscorlib.dll

I know this is confusing but we are creating psuedo sessions and the session id comes from a request and when the request is parsed it inserts the session id and the time and then starts the timer into a struct. The struct is then returned to the "main" class and then it is checked against other sessions in the session arraylist. If it is in the arraylist it removes the current and adds the new struct at the end of the arraylist. And then the new thread checks the arraylist to see if the session at index 0 of the arraylist has elapsed.

I hope this makes sense. If there is another implementation or way of doing it please let me know.

Thanks.

  • 3
    The code you have looks fine and there shouldn't be a problem with using a timer that is a property of a struct. You didn't show us, how you hooked up your event or created the instance of the timer. You also didn't specify the exact line of code where the exception happens or the full exception details including stacktrace and error message. – Daniel Hilgarth Apr 05 '11 at 16:57
  • 9
    _Mutable structs are **EVIL**!_ – SLaks Apr 05 '11 at 16:58
  • 1
    Your not showing how the struct is init and how the timer is created. – asawyer Apr 05 '11 at 16:58
  • @SLaks: Care to provide a link? (No, I didn't google :p) – Daniel Hilgarth Apr 05 '11 at 16:59
  • 3
    @Daniel: Roughly 1/3rd of Eric Lippert's blog posts. http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil http://blogs.msdn.com/b/ericlippert/archive/2008/05/14/mutating-readonly-structs.aspx http://blogs.msdn.com/b/ericlippert/archive/2011/03/29/compound-assignment-part-one.aspx – SLaks Apr 05 '11 at 17:00
  • I echo SLaks's comment. You should also think about equality - value types (structs) should usually implement value based equality and most Timer implementations do not do this. I think you should really review the use of a struct here instead of a class. However, these issues are orthogonal to your out of memory problem. – Adam Ralph Apr 05 '11 at 17:02
  • Um... I don't like that while loop... it looks suspicious. while(true)'s are the first place I would look for a memory problem – Ryan Bennett Apr 05 '11 at 18:10

1 Answers1

3

Yes, you can have a Timer (or any other type) be a member of a struct. Incidentally, you should strongly consider either changing this to be a class (is there any particular reason you made it a struct?) or removing the setters from your properties; mutable structs, as you have here, are generally regarded as Pure Evil.

There's not much here that actually tells anything about your environment and what might be causing you to run out of memory. Can you shed some more light on how you're actually using the struct?

Edit After Question Edit

You should not be attaching to the timer's event repeatedly as you are. Your while loop will continue to attach copies of the timer's handler, and this is likely where you're running out of memory.

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • that worked thanks a lot. However, im getting an argumentoutofrangeexception now when I shouldn't be? I don't know whether I can ask another question here but I maybe – Jonathan Harris Apr 06 '11 at 17:14
  • @Jonathan: You should probably open a new question. Please don't forget to mark this answer as accepted if it answered your question. – Adam Robinson Apr 06 '11 at 17:16