Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.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
.net ThreadLocal<&燃气轮机;和内存泄漏_.net_Memory Leaks_Thread Local - Fatal编程技术网

.net ThreadLocal<&燃气轮机;和内存泄漏

.net ThreadLocal<&燃气轮机;和内存泄漏,.net,memory-leaks,thread-local,.net,Memory Leaks,Thread Local,.Net 4。ThreadLocal实现IDisposable。但调用Dispose()似乎实际上并没有释放对所持有的线程本地对象的引用 此代码再现了以下问题: using System; using System.Collections.Generic; using System.Collections.Concurrent; using System.Linq; using System.Threading; namespace ConsoleApplication2 { clas

.Net 4。ThreadLocal实现IDisposable。但调用Dispose()似乎实际上并没有释放对所持有的线程本地对象的引用

此代码再现了以下问题:

using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;

namespace ConsoleApplication2
{
    class Program
    {
        class ThreadLocalData
        {
            // Allocate object in LOH
            public int[] data = new int[10 * 1024 * 1024];
        };

        static void Main(string[] args)
        {
            // Stores references to all thread local object that have been created
            var threadLocalInstances = new List<ThreadLocalData>();
            ThreadLocal<ThreadLocalData> threadLocal = new ThreadLocal<ThreadLocalData>(() =>
            {
                var ret = new ThreadLocalData();
                lock (threadLocalInstances)
                    threadLocalInstances.Add(ret);
                return ret;
            });
            // Do some multithreaded stuff
            int sum = Enumerable.Range(0, 100).AsParallel().Select(
                i => threadLocal.Value.data.Sum() + i).Sum();
            Console.WriteLine("Sum: {0}", sum);
            Console.WriteLine("Thread local instances: {0}", threadLocalInstances.Count);

            // Do our best to release ThreadLocal<> object
            threadLocal.Dispose();
            threadLocal = null;

            Console.Write("Press R to release memory blocks manually or another key to proceed: ");
            if (char.ToUpper(Console.ReadKey().KeyChar) == 'R')
            {
                foreach (var i in threadLocalInstances)
                    i.data = null;
            }
            // Make sure we don't keep the references to LOH objects
            threadLocalInstances = null;
            Console.WriteLine();

            // Collect the garbage
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            Console.WriteLine("Garbage collected. Open Task Manager to see memory consumption.");
            Console.Write("Press any key to exit.");
            Console.ReadKey();
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Collections.Concurrent;
使用System.Linq;
使用系统线程;
命名空间控制台应用程序2
{
班级计划
{
类ThreadLocalData
{
//在LOH中分配对象
公共整数[]数据=新整数[10*1024*1024];
};
静态void Main(字符串[]参数)
{
//存储对已创建的所有线程本地对象的引用
var threadLocationInstances=new List();
ThreadLocal ThreadLocal=新的ThreadLocal(()=>
{
var ret=new ThreadLocalData();
锁定(螺纹定位装置)
threadLocationInstances.Add(ret);
返回ret;
});
//做一些多线程的事情
int sum=Enumerable.Range(0,100).aspallel().Select(
i=>threadLocal.Value.data.Sum()+i.Sum();
WriteLine(“Sum:{0}”,Sum);
WriteLine(“线程本地实例:{0}”,threadLocalInstances.Count);
//尽最大努力释放ThreadLocal对象
threadLocal.Dispose();
threadLocal=null;
控制台。写入(“按R键手动释放内存块,或按另一个键继续:”);
if(char.ToUpper(Console.ReadKey().KeyChar)='R')
{
foreach(ThreadLocationInstances中的变量i)
i、 数据=空;
}
//确保我们没有保留对LOH对象的引用
ThreadLocationInstances=null;
Console.WriteLine();
//收集垃圾
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
WriteLine(“垃圾收集。打开任务管理器查看内存消耗。”);
控制台。写入(“按任意键退出”);
Console.ReadKey();
}
}
}
线程本地数据存储对大型对象的引用。如果引用没有手动为空,GC不会收集这些大型对象。我使用任务管理器来观察内存消耗。我还运行内存分析器。垃圾收集后我拍了一张快照。探查器显示泄漏的对象由GCHandle根目录,并在此处分配:

mscorlib!System.Threading.ThreadLocal<T>.GenericHolder<U,V,W>.get_Boxed()
mscorlib!System.Threading.ThreadLocal<T>.get_Value()
ConsoleApplication2!ConsoleApplication2.Program.<>c__DisplayClass3.<Main>b__2( int ) Program.cs
mscorlib!System.Threading.ThreadLocal.GenericHolder.get_Boxed()
mscorlib!System.Threading.ThreadLocal.get_值()
控制台应用程序2!控制台应用程序2.Program.c__显示类3.b___2(int)Program.cs

这似乎是ThreadLocal设计中的一个缺陷。存储所有分配的对象以进行进一步清理的技巧很难看。关于如何解决这个问题有什么想法吗?

内存可能已经被垃圾收集,但CLR进程还没有释放它。它倾向于保留分配的内存一段时间,以备以后需要,这样就不必进行昂贵的内存分配。

在.Net 4.5 DP上运行,我看不出在应用程序中按R与不按R之间有什么区别。如果4.0中确实存在内存泄漏,那么它似乎已经修复


(4.5是就地更新,因此我无法在同一台计算机上测试4.0,抱歉。)

您是在调试还是发布此版本?另外,任务管理器对于您正在测量的内容并不是非常有用。最好使用
GC.GetTotalMemory(true)
来测量内存,但这也不能保证收集所有内容。Printed GC.GetTotalMemory()。当我不将数据字段归零时,它会给出335607644,当我归零时,它会给出63268。没有显著差异。@SergeyS您应该使用新发现更新您的问题,并使用GC.GetTotalMemory,这样人们就不会被任务管理器方面拒绝。如果“数据”字段为零,GC的行为会有所不同。Plus Memory Profiler显示ThreadLocalData对象实际上是从ThreadLocal内部的某个地方扎根的。