0

I am trying to make a program that watches a folder for file creation events and does some processing on the files. My current implementation works using:

FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
fileSystemWatcher.Created += FileSystemWatcher_Created;

However, this seems to have memory leaks. Each time FileSystemWatcher_Created is called, the garbage collector does not dispose of it when it is done. I think that every instance of FileSystemWatcher_Created cannot be disposed of while the original FileSystemWatcher object still exists.

I don't think using fileSystemWatcher.Created -= FileSystemWatcher_Created; helps me in this case because I don't want FileSystemWatcher_Created to run only once. I want FileSystemWatcher_Created to run every time the file creation event happens. I just want the garbage collector to properly dispose of the memory that is used up for each instance.

I think this means that I want to use a WeakEventHandler to handle the event right? How do I do that in this context? I am using .NET Core but would still appreciate any .NET Framework answers.

Edit to add: FileSystemWatcher_Created. I am running a PowerShell script on the detected file and then moving it after processing.

private void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)

{
    //Get FileInfo object for newly detected file
    FileInfo file = new FileInfo(e.FullPath);
    
    //Wait until the file is able to be accessed
    while (IsFileLocked(file))
    {
        //If file is locked then wait 5 seconds and try again
        Thread.Sleep(5000);
    }
    
    //Run PowerShell script from PowerShell_Script_Path with the operation, CSV filepath, and EXE filepath as arguments
    ps.AddScript(File.ReadAllText(PowerShell_Script_Path)).AddArgument(GetOperation(e.Name)).AddArgument(e.FullPath).AddArgument(GetPath(Test_Mode)).Invoke();
    
    //Wait until the file is able to be accessed
    while (IsFileLocked(file))
    {
        //If file is locked then wait 10 seconds and try again
        Thread.Sleep(10000);
    }
    
    //Move file from pending folder to archive folder
    File.Move(e.FullPath, $"{Dst_Path}/{e.Name}", true);
}

After some trial and error, I get the least memory leaks by subscribing to the event with an anonymous function.

//Set File Watch File Creation Event Handler
fileSystemWatcher.Created += (object sender, FileSystemEventArgs e) =>
{
    //Get FileInfo object for newly detected file
    FileInfo file = new FileInfo(e.FullPath);
    
    //Wait until the file is able to be accessed
    while (IsFileLocked(file))
    {
        //If file is locked then wait 5 seconds and try again
        Thread.Sleep(5000);
    }
    
    //Run PowerShell script from PowerShell_Script_Path with the operation, CSV filepath, and EXE filepath as arguments
    ps.AddScript(File.ReadAllText(PowerShell_Script_Path)).AddArgument(GetOperation(e.Name)).AddArgument(e.FullPath).AddArgument(GetPath(Test_Mode)).Invoke();
    
    //Wait until the file is able to be accessed
    while (IsFileLocked(file))
    {
        //If file is locked then wait 10 seconds and try again
        Thread.Sleep(10000);
    }
    
    //Move file from pending folder to archive folder
    File.Move(e.FullPath, $"{Dst_Path}/{e.Name}", true);
}
               
function9
  • 19
  • 5
  • Are you watching more than 1 folder? If you are watching only one folder, it will fire a Created event every time a new file or sub folder is created. It doesn't just stop generating events after the events. It keeps generating events until you stop monitoring the folder. – B.O.B. Jan 27 '22 at 00:22
  • I am watching just 1 folder. Firing a Created event every time a new file is created is what I want it to do. What I don't want it to do is memory leak until the FileSystemWatcher object is disposed of. – function9 Jan 27 '22 at 00:30
  • 1
    I'm confused. `FileSystemWatcher_Created` is a method, encapsulated in a delegate *one time.* It's not a thing that is created at each call. What is it you think that should be garbage collected? – Corey Jan 27 '22 at 00:49
  • @TheodorZoulias Added the code for you. – function9 Jan 27 '22 at 00:56
  • @Corey It could be that I have a memory leak from something that I am doing inside ```FileSystemWatcher_Created``` and I am misattributing the memory leak to Strong and Weak events. – function9 Jan 27 '22 at 00:57
  • 1
    When you say you have a memory leak, what do you mean exactly? Can you describe the symptoms you are having? – Robert Harvey Jan 27 '22 at 00:58
  • You are doing too much work inside the handler. The [documentation](https://learn.microsoft.com/en-us/dotnet/api/system.io.filesystemwatcher#events-and-buffer-sizes) recommends to keep the event handling code as short as possible. Using `await Task.Delay()` instead of `Thread.Sleep()` might help. You may want to check out [this](https://stackoverflow.com/questions/66258633/filesystemwatcher-not-working-even-once-except-for-root-folder-having-320k-subdi "FileSystemWatcher not working even once except for root folder having 320K subdirectories") question also. – Theodor Zoulias Jan 27 '22 at 01:09
  • @RobertHarvey I did a memory diagnostic and took [snapshots](https://i.imgur.com/1aIdjYu.png) each time ```FileSystemWatcher_Created``` processed a file. To me, this seems like there is a memory leak each time the file is processed, maybe I'm wrong. – function9 Jan 27 '22 at 01:09
  • 1
    Weak events are useful for a situation where the object hosting the event handler can be disposed without unhooking the handler. It's not going to help with your problem. If there's a leak then it's either in the parameters being passed to your handler or in your handler code, not in the event handling. – Corey Jan 27 '22 at 02:25
  • 1
    When handling events from `FileSystemWatcher` you should never run a long-running process before returning. If you absolutely must do long-running processing, add a queue and a worker that monitors it so that your handler just queues up the event data for further processing then return. – Corey Jan 27 '22 at 02:27
  • Could you also include the `IsFileLocked` method in the question? – Theodor Zoulias Jan 27 '22 at 03:16

0 Answers0