Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用线程时内存泄漏_C#_.net_Multithreading_Memory_Timer - Fatal编程技术网

C# 使用线程时内存泄漏

C# 使用线程时内存泄漏,c#,.net,multithreading,memory,timer,C#,.net,Multithreading,Memory,Timer,我在这段代码中似乎有内存泄漏。它是一个控制台应用程序,创建两个类(WorkerThread),每个类都以指定的间隔写入控制台。Timer用于执行此操作,因此对控制台的写入在单独的线程中执行(TimerCallback在从线程池中获取的单独线程中调用)。使事情复杂化的是,MainThread类钩住FileSystemWatcher的已更改事件;当test.xml文件更改时,将重新创建WorkerThread类 每次保存文件时(每次重新创建WorkerThread和计时器时),任务管理器中的内存都会

我在这段代码中似乎有内存泄漏。它是一个控制台应用程序,创建两个类(WorkerThread),每个类都以指定的间隔写入控制台。Timer用于执行此操作,因此对控制台的写入在单独的线程中执行(TimerCallback在从线程池中获取的单独线程中调用)。使事情复杂化的是,MainThread类钩住FileSystemWatcher的已更改事件;当test.xml文件更改时,将重新创建WorkerThread类

每次保存文件时(每次重新创建WorkerThread和计时器时),任务管理器中的内存都会增加(Mem使用量,有时还会增加VM大小);此外,在.Net Memory Profiler(v3.1)中,WorkerThread类的未分发实例增加了两个(不过这可能是一个转移注意力的问题,因为我读到.Net Memory Profiler有一个bug,它很难检测已分发的类)

不管怎样,这是代码-有人知道出了什么问题吗

编辑:我已将类创建移出FileSystemWatcher。更改了事件处理程序,这意味着WorkerThread类始终在同一个线程中创建。我已为静态变量添加了一些保护。我还提供了线程信息,以更清楚地显示正在发生的事情,并已进行了交互g使用计时器和显式线程;但是,内存仍在泄漏!Mem使用量一直在缓慢增加(这仅仅是因为控制台窗口中有额外的文本吗?),并且当我更改文件时,VM大小会增加。下面是最新版本的代码:

编辑这似乎主要是控制台在写入时内存不足的问题。显式写入的线程增加内存使用率仍然存在问题。请参阅

类程序
{
私有静态列表线程=新列表();
静态void Main(字符串[]参数)
{
MainThread.Start();
}
}
公共类主线程
{
私有静态int_eventsRaised=0;
私有静态int_事件响应=0;
私有静态bool_reload=false;
私有静态只读对象_reloadLock=新对象();
//不过,在处理程序中只做一次
//此代码将在windows服务的onStart中输入。
公共静态void Start()
{
WorkerThread thread1=null;
WorkerThread thread2=null;
WriteLine(“开始:线程”+thread.CurrentThread.ManagedThreadId);
//手表配置
FileSystemWatcher watcher=新的FileSystemWatcher();
watcher.Path=“../”;
watcher.Filter=“test.xml”;
watcher.EnableRaisingEvents=true;
//订阅已更改的事件。请注意,每次保存文件都会引发多次此事件。
watcher.Changed+=(发送方,参数)=>FileChanged(发送方,参数);
thread1=新的WorkerThread(“foo”,10);
螺纹2=新的工作螺纹(“bar”,15);
while(true)
{
如果(_重新加载)
{
//创建我们的两个线程。
WriteLine(“开始-重新加载:线程”+thread.CurrentThread.ManagedThreadId);
//等待,以允许其他文件更改事件通过
WriteLine(“开始-等待:线程”+thread.CurrentThread.ManagedThreadId);
thread1.Dispose();
thread2.Dispose();
Thread.Sleep(3000);//每个线程持续0.5秒,因此等待
//要完成的LoadData函数。
监视器。输入(_reloadLock);
thread1=新的WorkerThread(“foo”,10);
螺纹2=新的工作螺纹(“bar”,15);
_重新加载=错误;
监视器退出(_reloadLock);
}
}
}
//在单独的线程中调用此事件处理程序以启动()
静态无效文件已更改(对象源、文件系统目标)
{
监视器。输入(_reloadLock);
_eventsRaised+=1;
//如果距离上次事件(即,这是新的保存)已超过一秒钟,则等待3秒钟(以避免
//处理前,同一文件的多个事件(保存)
如果(!\u重新加载)
{
WriteLine(“FileChanged:thread”+thread.CurrentThread.ManagedThreadId);
_事件响应+=1;
WriteLine(“FileChanged.Handled事件{0}of{1}.”,_eventsrespondento,_eventsRaised);
//告诉主线程重新启动线程
_重新加载=真;
}
监视器退出(_reloadLock);
}
}
公共类WorkerThread:IDisposable
{
private System.Threading.Timer Timer;//计时器存在于其单独的线程池线程中。
私有字符串_name=string.Empty;
private int _interval=0;//线程等待间隔(毫秒)。
私有线程_Thread=null;
私有ThreadStart _job=null;
公共WorkerThread(字符串名称,int间隔)
{
WriteLine(“WorkerThread:thread”+thread.CurrentThread.ManagedThreadId);
_名称=名称;
_间隔=间隔*1000;
_作业=新线程开始(加载数据);
_线程=新线程(_作业);
_thread.Start();
//定时器=新定时器(滴答,空,1000,间隔*1000);
}
//此委托实例与创建计时器的线程不在同一线程中运行。它在自己的线程中运行
//线程,取自线程池。因此,无需为LoadData方法创建新线程。
私有无效勾号(对象状态)
{
//LoadData();
}
//加载数据。从单独的线程调用。持续0.5秒。
//
//私有void LoadData(对象状态)
私有void LoadData()
{
while(true)
{
对于(int i=0;i<10;i++)
{
class Program
{
    private static List<WorkerThread> threads = new List<WorkerThread>();

    static void Main(string[] args)
    {
        MainThread.Start();

    }
}

public class MainThread
{
    private static int _eventsRaised = 0;
    private static int _eventsRespondedTo = 0;
    private static bool _reload = false;
    private static readonly object _reloadLock = new object();
    //to do something once in handler, though
    //this code would go in onStart in a windows service.
    public static void Start()
    {
        WorkerThread thread1 = null;
        WorkerThread thread2 = null;

        Console.WriteLine("Start: thread " + Thread.CurrentThread.ManagedThreadId);
        //watch config
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = "../../";
        watcher.Filter = "test.xml";
        watcher.EnableRaisingEvents = true;
        //subscribe to changed event. note that this event can be raised a number of times for each save of the file.
        watcher.Changed += (sender, args) => FileChanged(sender, args);

        thread1 = new WorkerThread("foo", 10);
        thread2 = new WorkerThread("bar", 15);

        while (true)
        {
            if (_reload)
            {
                //create our two threads.
                Console.WriteLine("Start - reload: thread " + Thread.CurrentThread.ManagedThreadId);
                //wait, to enable other file changed events to pass
                Console.WriteLine("Start - waiting: thread " + Thread.CurrentThread.ManagedThreadId);
                thread1.Dispose();
                thread2.Dispose();
                Thread.Sleep(3000); //each thread lasts 0.5 seconds, so 3 seconds should be plenty to wait for the 
                                    //LoadData function to complete.
                Monitor.Enter(_reloadLock);
                thread1 = new WorkerThread("foo", 10);
                thread2 = new WorkerThread("bar", 15);
                _reload = false;
                Monitor.Exit(_reloadLock);
            }
        }
    }

    //this event handler is called in a separate thread to Start()
    static void FileChanged(object source, FileSystemEventArgs e)
    {
        Monitor.Enter(_reloadLock);
        _eventsRaised += 1;
        //if it was more than a second since the last event (ie, it's a new save), then wait for 3 seconds (to avoid 
        //multiple events for the same file save) before processing
        if (!_reload)
        {
            Console.WriteLine("FileChanged: thread " + Thread.CurrentThread.ManagedThreadId);
            _eventsRespondedTo += 1;
            Console.WriteLine("FileChanged. Handled event {0} of {1}.", _eventsRespondedTo, _eventsRaised);
            //tell main thread to restart threads
            _reload = true;
        }
        Monitor.Exit(_reloadLock);
    }
}

public class WorkerThread : IDisposable
{
    private System.Threading.Timer timer;   //the timer exists in its own separate thread pool thread.
    private string _name = string.Empty;
    private int _interval = 0;  //thread wait interval in ms.
    private Thread _thread = null;
    private ThreadStart _job = null;

    public WorkerThread(string name, int interval)
    {
        Console.WriteLine("WorkerThread: thread " + Thread.CurrentThread.ManagedThreadId);
        _name = name;
        _interval = interval * 1000;
        _job = new ThreadStart(LoadData);
        _thread = new Thread(_job);
        _thread.Start();
        //timer = new Timer(Tick, null, 1000, interval * 1000);
    }

    //this delegate instance does NOT run in the same thread as the thread that created the timer. It runs in its own
    //thread, taken from the ThreadPool. Hence, no need to create a new thread for the LoadData method.
    private void Tick(object state)
    {
        //LoadData();
    }

    //Loads the data. Called from separate thread. Lasts 0.5 seconds.
    //
    //private void LoadData(object state)
    private void LoadData()
    {
        while (true)
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(string.Format("Worker thread {0} ({2}): {1}", _name, i, Thread.CurrentThread.ManagedThreadId));
                Thread.Sleep(50);
            }
            Thread.Sleep(_interval);
        }
    }

    public void Stop()
    {
        Console.WriteLine("Stop: thread " + Thread.CurrentThread.ManagedThreadId);
        //timer.Dispose();
        _thread.Abort();
    }


    #region IDisposable Members

    public void Dispose()
    {
        Console.WriteLine("Dispose: thread " + Thread.CurrentThread.ManagedThreadId);
        //timer.Dispose();
        _thread.Abort();
    }

    #endregion
}
static void test()
{
    _eventsRaised += 1;
    //if it was more than a second since the last event (ie, it's a new save), then wait for 3 seconds (to avoid 
    //multiple events for the same file save) before processing
    if (DateTime.Now.Ticks - _lastEventTicks > 1000)
    {
        Thread.Sleep(3000);
        _lastEventTicks = DateTime.Now.Ticks;
        _eventsRespondedTo += 1;
        Console.WriteLine("File changed. Handled event {0} of {1}.", _eventsRespondedTo, _eventsRaised);
        //stop threads and then restart them
        thread1.Stop();
        thread2.Stop();
        thread1 = new WorkerThread("foo", 20);
        thread2 = new WorkerThread("bar", 30);
    }
}
public class ThreadUsingClass
{
    private object mSyncObject = new object();
    private bool mKilledThread = false;
    private Thread mThread = null;

    void Start()
    {
        // start mThread
    }

    void Stop()
    {
        lock(mSyncObject)
        {
            mKilledThread = true;
        }

        mThread.Join();
    }

    void ThreadProc()
    {
        while(true)
        {
            bool isKilled = false;
            lock(mSyncObject)
            {
                isKilled = mKilledThread;
            }
            if (isKilled)
                return;
        }
    }    
}
class Program
{
    static void Main(string[] args)
    {
        MainThread.Start();

    }
}

public class MainThread
{
    private static int _eventsRaised = 0;
    private static int _eventsRespondedTo = 0;
    private static bool _reload = false;
    private static readonly object _reloadLock = new object();
    //to do something once in handler, though
    //this code would go in onStart in a windows service.
    public static void Start()
    {
        WorkerThread thread1 = null;
        WorkerThread thread2 = null;
        //WorkerTimer thread1 = null;
        //WorkerTimer thread2 = null;

        //Console.WriteLine("Start: thread " + Thread.CurrentThread.ManagedThreadId);
        //watch config
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = "../../";
        watcher.Filter = "test.xml";
        watcher.EnableRaisingEvents = true;
        //subscribe to changed event. note that this event can be raised a number of times for each save of the file.
        watcher.Changed += (sender, args) => FileChanged(sender, args);

        thread1 = new WorkerThread("foo", 10);
        thread2 = new WorkerThread("bar", 15);
        //thread1 = new WorkerTimer("foo", 10);
        //thread2 = new WorkerTimer("bar", 15);

        while (true)
        {
            if (_reload)
            {
                //create our two threads.
                //Console.WriteLine("Start - reload: thread " + Thread.CurrentThread.ManagedThreadId);
                //wait, to enable other file changed events to pass
                //Console.WriteLine("Start - waiting: thread " + Thread.CurrentThread.ManagedThreadId);
                thread1.Dispose();
                thread2.Dispose();
                Thread.Sleep(3000); //each thread lasts 0.5 seconds, so 3 seconds should be plenty to wait for the 
                //LoadData function to complete.
                Monitor.Enter(_reloadLock);
                //GC.Collect();
                thread1 = new WorkerThread("foo", 5);
                thread2 = new WorkerThread("bar", 7);
                //thread1 = new WorkerTimer("foo", 5);
                //thread2 = new WorkerTimer("bar", 7);
                _reload = false;
                Monitor.Exit(_reloadLock);
            }
        }
    }

    //this event handler is called in a separate thread to Start()
    static void FileChanged(object source, FileSystemEventArgs e)
    {
        Monitor.Enter(_reloadLock);
        _eventsRaised += 1;
        //if it was more than a second since the last event (ie, it's a new save), then wait for 3 seconds (to avoid 
        //multiple events for the same file save) before processing
        if (!_reload)
        {
            //Console.WriteLine("FileChanged: thread " + Thread.CurrentThread.ManagedThreadId);
            _eventsRespondedTo += 1;
            //Console.WriteLine("FileChanged. Handled event {0} of {1}.", _eventsRespondedTo, _eventsRaised);
            //tell main thread to restart threads
            _reload = true;
        }
        Monitor.Exit(_reloadLock);
    }
}

public class WorkerTimer : IDisposable
{
    private System.Threading.Timer _timer;   //the timer exists in its own separate thread pool thread.
    //private System.Timers.Timer _timer;
    private string _name = string.Empty;

    /// <summary>
    /// Initializes a new instance of the <see cref="WorkerThread"/> class.
    /// </summary>
    /// <param name="name">The name.</param>
    /// <param name="interval">The interval, in seconds.</param>
    public WorkerTimer(string name, int interval)
    {
        _name = name;
        //Console.WriteLine("WorkerThread constructor: Called from thread " + Thread.CurrentThread.ManagedThreadId);
        //_timer = new System.Timers.Timer(interval * 1000);
        //_timer.Elapsed += (sender, args) => LoadData();
        //_timer.Start();
        _timer = new Timer(Tick, null, 1000, interval * 1000);
    }

    //this delegate instance does NOT run in the same thread as the thread that created the timer. It runs in its own
    //thread, taken from the ThreadPool. Hence, no need to create a new thread for the LoadData method.
    private void Tick(object state)
    {
        LoadData();
    }

    //Loads the data. Called from separate thread. Lasts 0.5 seconds.
    //
    private void LoadData()
    {
        for (int i = 0; i < 10; i++)
        {
            //Console.WriteLine(string.Format("Worker thread {0} ({2}): {1}", _name, i, Thread.CurrentThread.ManagedThreadId));
            Thread.Sleep(50);
        }
    }

    public void Stop()
    {
        //Console.WriteLine("Stop: called from thread " + Thread.CurrentThread.ManagedThreadId);
        //_timer.Stop();
        _timer.Change(Timeout.Infinite, Timeout.Infinite);
        //_timer = null;
        //_timer.Dispose();
    }


    #region IDisposable Members

    public void Dispose()
    {
        //Console.WriteLine("Dispose: called from thread " + Thread.CurrentThread.ManagedThreadId);
        //_timer.Stop();
        _timer.Change(Timeout.Infinite, Timeout.Infinite);
        //_timer = null;
        //_timer.Dispose();
    }

    #endregion
}

public class WorkerThread : IDisposable
{
    private string _name = string.Empty;
    private int _interval = 0;  //thread wait interval in ms.
    private Thread _thread = null;
    private ThreadStart _job = null;
    private object _syncObject = new object();
    private bool _killThread = false;

    public WorkerThread(string name, int interval)
    {
        _name = name;
        _interval = interval * 1000;
        _job = new ThreadStart(LoadData);
        _thread = new Thread(_job);
        //Console.WriteLine("WorkerThread constructor: thread " + _thread.ManagedThreadId + " created. Called from thread " + Thread.CurrentThread.ManagedThreadId);
        _thread.Start();
    }

    //Loads the data. Called from separate thread. Lasts 0.5 seconds.
    //
    //private void LoadData(object state)
    private void LoadData()
    {
        while (true)
        {
            //check to see if thread it to be stopped.
            bool isKilled = false;

            lock (_syncObject)
            {
                isKilled = _killThread;
            }

            if (isKilled)
                return;

            for (int i = 0; i < 10; i++)
            {
                //Console.WriteLine(string.Format("Worker thread {0} ({2}): {1}", _name, i, Thread.CurrentThread.ManagedThreadId));
                Thread.Sleep(50);
            }
            Thread.Sleep(_interval);
        }
    }

    public void Stop()
    {
        //Console.WriteLine("Stop: thread " + _thread.ManagedThreadId + " called from thread " + Thread.CurrentThread.ManagedThreadId);
        //_thread.Abort();
        lock (_syncObject)
        {
            _killThread = true;
        }
        _thread.Join();
    }


    #region IDisposable Members

    public void Dispose()
    {
        //Console.WriteLine("Dispose: thread " + _thread.ManagedThreadId + " called from thread " + Thread.CurrentThread.ManagedThreadId);
        //_thread.Abort();
        lock (_syncObject)
        {
            _killThread = true;
        }
        _thread.Join();
    }

    #endregion
}