Windows 10上的.NET FontFamily内存泄漏

时间:2015-10-29 14:18:59

标签: c# .net memory-leaks windows-10 font-family

在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();
        }
    }
}

有关为何发生这种情况的任何想法?

提前致谢!

3 个答案:

答案 0 :(得分:0)

如果内存泄漏会出现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);

答案 1 :(得分:0)

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

<div class="wrapper">
  <div class="ideas__gallery">
    <h3 class="ideas__gallery__h3">Headline</h3>
    <div class="one"></div>
    <div class="two"></div>
    <div class="three"></div>
    <div class="four"></div>
    <div class="five"></div>
    <div class="six"></div>
    <div class="seven"></div>
  </div>
</div>

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

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);
}

答案 2 :(得分:0)

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

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

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