C#线程在完成后如何导致内存泄漏?

时间:2015-02-27 16:38:30

标签: c# multithreading memory-leaks mono xamarin

这是我的代码:

using System;
using System.Collections.Generic;
using System.Threading;
namespace testt
{
    class MainClass
    {
        public static List<TestObject> testjobs = new List<TestObject> ();
        public static void Main (string[] args)
        {
            Console.WriteLine ("Hello World!");
            addTask (); //put a breakpoint here
            Thread.Sleep (5000);
            deleteObj ();
            while (true) {
                Console.WriteLine ("MAIN STILL EXISTS!");
                Thread.Sleep (1500);
                GC.Collect ();
            }
        }
        public static void addTask()
        {
            for (int i = 0; i < 10; i++)
            {
                testjobs.Add (new TestObject ());
                testjobs [i].Start ();
            }
        }

        public static void deleteObj()
        {
            for(int i=0; i<10;i++)
            {
                testjobs [0].dispose ();
                testjobs.RemoveAt (0);
            }
            Console.WriteLine (testjobs.Count);
        }

    }

    public class TestObject
    {

        private bool _isStopRequested;
        private Thread _thread;
        public void Start()
        {
            _thread = new Thread(ThreadRoutine);
            _thread.Start();
        }

        public void Stop()
        {
            _isStopRequested = true;
            if(!_thread.Join(5000))
            {
                _thread.Abort();
            }
        }

        public void dispose(){
            this.Stop ();
            this._thread.Abort ();
            this._thread=null;
        }


        private void ThreadRoutine()
        {
            //while(!_isStopRequested) //THIS CAUSES THE MEMORY LEAK!!!
            {
            Thread.Sleep (1);
            }
            Console.WriteLine ("THREAD FINISHED");
        }

        ~TestObject(){
            Console.WriteLine ("===================TESTOBJECT DESTROYED!!===============");
        }
    }
}

如果在未注释//while(!_isStopRequested)的情况下运行它,TestObject实例将不会被销毁,即不会调用它们的析构函数方法。

如果按原样运行,那么只会破坏4-8个对象,而不是全部10个。

为什么线程完全退出后会发生这种情况?我检查了Xamarin调试器,线程肯定停止了。如果你在addMask()中在Xamarin中放置一个断点;然后你可以看到10个线程

我对此的唯一解释是,线程以某种方式将引用返回到它们的父对象TestObject实例,即使它们已经完成。当线程已经完成时,线程如何保存对其父对象的引用?

此外,如果我将Thread.Sleep(1)更改为Thread.Sleep(5000),则TestObjects也会停止收集。

另外,实际上,只有一些TestObjects被收集而其他人没有收集。

为什么会发生这些事情?如何在deleteObj()函数返回时确保所有TestObjects都收集垃圾?

编辑:我刚刚在Visual Studio(.NET)中测试了完全相同的代码,所有对象都被垃圾收集,无论该行是否被注释掉。

因此,我现在认为这个问题是一个特定于Mono的问题,并且开始时没有内存泄漏。

1 个答案:

答案 0 :(得分:3)

终结者不是确定性的。你不能依赖他们被召唤。

如果您的程序清理有问题的资源至关重要,那么您应该明确处理它,而不是依赖终结器。

如果清理资源会很好,但是如果终端连接器没有达到它那么你真的不在乎那么多,那么你可以选择不显式处理非托管资源。

另请注意,使托管对象符合条件进行垃圾回收并不一定意味着它将被垃圾回收。这意味着只要收藏家感觉它就可以收集

最后,要认识到中止线程是另一个不可靠的事情。线程呢。对于被请求中止的线程,有多种方法不会成功执行,或者它会导致任何数量的不同类型的问题。您应该避免使用Thread.Abort,除非有问题的线程被设计为中止,并且您对尝试推理可能在任何两个操作之间引发异常的程序的所有许多可能缺陷有深刻的理解。