Reputation: 1171
I was reading @supercat's post here https://stackoverflow.com/a/10317035 and I had a question regarding the following:
It's important to note that even objects which only interact with 100% managed objects can do things that need to be cleaned up (and should use IDisposable). For example, an IEnumerator which attaches to a collection's "modified" event will need to detach itself when it is no longer needed. Otherwise, unless the enumerator uses some complex trickery, the enumerator will never be garbage-collected as long as the collection is in scope. If the collection is enumerated a million times, a million enumerators would get attached to its event handler.
I currently have a very very very slow memory leak in my code and I'm having a hell of a time isolating it (it takes at least 12 hours to notice a trend in private memory and at least 3 days at full-steam before it will throw an OutOfMemoryException). I think it might be related to what @supercat mentioned about internally subscribing to an event, except I am dealing with C# and not VB. In the production code the GC cleans up the memory if the while-loop exits, but not before then.
In the following code, are there any event handlers getting subscribed to behind the scenes?
Does anything in the two loops look like a managed-leak?
Does Directory.EnumerateFiles()
have odd memory-usage behaviour?
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace DoForeachWhile_Test
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press any key to begin. Press Escape to stop the program.");
ConsoleKeyInfo KeyPressed = Console.ReadKey();
while (KeyPressed.Key != ConsoleKey.Escape)
{
IEnumerable<string> SomeIteration = Directory.EnumerateFiles(@"C:\"); // new List<string>() { "1", "2", "3", "4", "5" };
foreach (var StringItem in SomeIteration)
{
Console.WriteLine(StringItem);
}
//Thread.Sleep(10);
Console.Clear();
if (Console.KeyAvailable)
KeyPressed = Console.ReadKey(true);
}
Console.WriteLine("Press any key to exit the program.");
Console.ReadKey();
}
}
}
Upvotes: 2
Views: 1233
Reputation: 1350
As the comments say, I also don't think there's a memory leak in your loops.
But what about this part: What if RunningOTS.StartWork(...)
throws an exception? Should you then call RunningOTS.EndWork(...)
passing a possibly invalid WorkStartHandle
?
Normally I would write a block like this like
try
{
WorkStartHandle =
RunningOTS.StartWork(p_waitForStartAcknowledge: true);
// do { } while ( )
RunningOTS.EndWork(WorkStartHandle);
}
finally
{
Log
.FormattedLine(MessageScope.Nests,
"{0} :: RunToken {1}", NestID, RunningOTS);
}
However, this may not work for you because I don't know if you might get an exception thrown in your do while
. It may be that you get an exception thrown by a line other than RunningOTS.StartWork(...)
, and you do need to call RunningOTS.EndWork(...)
.
My best suggestion, then, is to somehow test if WorkStartHandle
is valid in the finally
block. Presuming this is a handle like many others,
if (WorkStartHandle >= 0) // valid handle?
RunningOTS.EndWork(WorkStartHandle)
...may work.
Upvotes: 0