.Net 4. ThreadLocal <> triển khai IDisposable. Nhưng có vẻ như việc gọi Dispose() không thực sự giải phóng các tham chiếu đến các đối tượng địa phương luồng đang được giữ.ThreadLocal <> và rò rỉ bộ nhớ
Mã này tái tạo các vấn đề:
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();
}
}
}
Chủ đề lưu trữ dữ liệu địa phương một tham chiếu đến một đối tượng lớn. GC không thu thập các đối tượng lớn này nếu tham chiếu không bị vô hiệu theo cách thủ công. Tôi đã sử dụng Trình quản lý tác vụ để quan sát mức tiêu thụ bộ nhớ. Tôi cũng chạy bộ nhớ hồ sơ. Tôi đã chụp nhanh sau khi thu gom rác. Các hồ sơ cho thấy, đối tượng bị rò rỉ là bắt nguồn từ bởi GCHandle và được phân bổ với ở đây:
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
Đó có vẻ là một lỗ hổng trong ThreadLocal <> thiết kế. Bí quyết với việc lưu trữ tất cả các đối tượng được phân bổ để làm sạch thêm là xấu xí. Bất kỳ ý tưởng về cách làm việc xung quanh đó?
Bạn đang gỡ lỗi hoặc phát hành cho điều này? Ngoài ra, quản lý tác vụ không thực sự rất hữu ích cho những gì bạn đang đo –
Bạn nên sử dụng 'GC.GetTotalMemory (true)' để đo bộ nhớ, nhưng điều đó cũng không đảm bảo rằng mọi thứ sẽ được thu thập. – Ray
Đã in GC.GetTotalMemory(). Nó cho 335607644 khi tôi không số không ** dữ liệu ** lĩnh vực và 63268 khi tôi làm. – SergeyS