I have had a customer report to me an issue related to memory not being released when the page is closed. I have since verified this. I can open pages in my web app, see the memory increase and then not get released when the page is closed. It is a standalone web app. I have looked at all my objects and everything and I cannot find any references to pages that have been closed. None of my AddHandler directives reference anything outside the page they are on. None of my app properties are referencing anything on a page.
Initially I discovered a bug where I was keeping references to sessions but not destroying them when a session closed. I thought that was the source of my memory leak - having references to all the sessions in the app object. I eliminated that code but that didn’t solve the problem.
But I think I may have found the issue but I don’t know how to fix it. Or maybe it’s another issue and unrelated. So I am asking for some help here.
I see an occasional exception being raised that I just don’t understand. Let me explain.
I am using Aaron Ballman’s ThreadPoolManager class to implement some thread pooling in the App object of the web app. At the point in question of when these pages are closing, the ThreadPoolManager is basically idle. Here’s the run code from the ThreadPoolManager Thread:
// We want to loop forever; once there's a manager, // there's always a manager while Not KillMe // Check to see if we've got any items in our work queue if UBound( mWorkQueue ) >= 0 then // Check to see if we've got any free threads in the pool dim freeThread as ThreadPoolThread = GetFreeThreadFromPool //TimesAsleep = 0 if freeThread <> nil then // We have a thread free, so we want to tell it // to do some work freeThread.SetWorker( mWorkQueue( 0 ) ) // Remove the work item mWorkQueue.Remove( 0 ) 'System.DebugLog("About to run new Thread - Thread Number "+str(mWorkQueue.Ubound)) // And run the thread freeThread.Run Dim n as integer = 0 For i as integer = 0 to mThreadPool.Ubound If mThreadPool(i).State <> Thread.NotRunning Then n = n+1 End If Next If n > MaxNumThreads Then MaxNumThreads = n else // No free threads. We could boost the number of threads // available in our pool. But we're just going to sleep for // a while instead. me.Sleep( 1000, true ) end if else // Check to see if the user has changed any of our // hints or not if me.mHintsChanged then // We may need to resize our thread pool, or modify // some priorities of non-running threads. UpdatePool end if //TimesAsleep = TimesAsleep+1 // //If TimesAsleep = 10 Then //me.Suspend //End If #Pragma BreakOnExceptions Off // We don't have any work to do - suspend // ADDED TRY BLOCK BECAUSE OF THE EXCEPTION HERE THAT IS THROWN AFTER A PAGE CLOSES Try me.Suspend // ->>> This is where the exception is being thrown. And even with the Pragma // ->>> the app still breaks. Catch Try me.sleep(1000) Catch End Try End Try #Pragma BreakOnExceptions On end if wend
So where the Try block is at is where the exception occurs. So I get a Nil object exception. Why? The ThreadPoolManager exists (it’s a singleton). And it shows as existing in the debugger too. And the break happens even with the Pragma statement.
It happens after a page closes. The exception stack trace is below:
It looks to me that it’s happening in the destructor method of WebGraphics. Looks like there’s an event handler not being removed correctly. So I think what is happening with my memory is this exception is being thrown and the objects are not really being destructed and cleaned up. They are still there in memory.
Might this be what is happening?
Do I need to file a bug report?