Windows 10上的.NET FontFamily内存泄漏

在Windows 10上,即使在调用Dispose方法之后,System.Drawing.FontFamily.IsStyleAvailable方法似乎也将分配的空间留在内存中。

我写了一个简单的控制台应用程序来测试它:

using System; using System.Drawing; using System.Diagnostics; namespace ConsoleApplication1 { class Program { static string getMemoryStatusString() { using (Process p = Process.GetCurrentProcess()) { return "(p: " + p.PrivateMemorySize64 + ", v:" + p.VirtualMemorySize64 + ")"; } } static void Main(string[] args) { string s = getMemoryStatusString(); foreach(FontFamily fontFamily in FontFamily.Families) { Console.Write(fontFamily.Name + " " + getMemoryStatusString() + " -> "); fontFamily.IsStyleAvailable(FontStyle.Regular); fontFamily.Dispose(); Console.WriteLine(getMemoryStatusString()); } string e = getMemoryStatusString(); Console.WriteLine(s + " -> " + e); Console.ReadLine(); } } } 

知道为什么会这样吗?

提前致谢!

如果有内存泄漏,它将在gdiplus.dllFontFamily.IsStyleAvailable()实际上对GdipIsStyleAvailable()进行外部调用。

来自ILSpy:

 public bool IsStyleAvailable(FontStyle style) { int num2; int num = SafeNativeMethods.Gdip.GdipIsStyleAvailable(new HandleRef(this, this.NativeFamily), style, out num2); if (num != 0) { throw SafeNativeMethods.Gdip.StatusException(num); } return num2 != 0; } 

这反过来定义为:

 [DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] internal static extern int GdipIsStyleAvailable(HandleRef family, FontStyle style, out int isStyleAvailable); 

我在工作站上看不到任何泄漏(但我使用的是带有.Net 4.5的 Windows 7 )。 测试程序存在一些问题

 static string getMemoryStatusString() { // Do not forget to collect the garbage (all the generations) GC.Collect(2); GC.WaitForFullGCComplete(); using (Process p = Process.GetCurrentProcess()) { return "(p: " + p.PrivateMemorySize64 + ", v:" + p.VirtualMemorySize64 + ")"; } } // Suspected method static void methodUnderTest() { foreach (FontFamily fontFamily in FontFamily.Families) { //Console.Write(fontFamily.Name + " " + getMemoryStatusString() + " -> "); fontFamily.IsStyleAvailable(FontStyle.Regular); //TODO: You must not do this: disposing instanse you don't own fontFamily.Dispose(); } } // Test itself static void Main(string[] args) { // Warming up: let all the libraries (dll) be loaded, // caches fed, prefetch (if any) done etc. for (int i = 0; i < 10; ++i) methodUnderTest(); // Now, let's run the test: just one execution more // if you have a leak, s1 and s2 will be different // since each run leads to leak of number of bytes string s1 = getMemoryStatusString(); methodUnderTest(); string s2 = getMemoryStatusString(); Console.Write(s1 + " -> " + s2); } 

我看到之后的内存等于内存之后:

  (p: 59453440, v:662425600) -> (p: 59453440, v:662425600) 

调用dispose不会立即释放管理内存。 它必须等到GC.Collect发生。 如果要在Disposing之后测量内存,则应强制执行GC.Collect并等待最终确定。

在处理内存读取和查看后,执行强制垃圾收集,如下所示。

 GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect();