当通过WriteableBitmap处理小文件(
尽管这不是小型应用程序中的主要瓶颈,但是当内存中存在数千个对象时,它成为一个非常大的问题(应用程序在99.75%的“%Time in GC时间”中冻结几秒钟)(例如: cc>包含许多实体和关系的上下文)。

综合测试:

var objectCountPressure = (
    from x in Enumerable.Range(65, 26)
    let root = new DirectoryInfo((char)x + ":\\")
    let subs =
        from y in Enumerable.Range(0, 100 * IntPtr.Size)
        let sub =new {DI = new DirectoryInfo(Path.Combine(root.FullName, "sub" + y)), Parent = root}
        let files = from z in Enumerable.Range(0, 400) select new {FI = new FileInfo(Path.Combine(sub.DI.FullName, "file" + z)), Parent = sub}
        select new {sub, files = files.ToList()}
    select new {root, subs = subs.ToList()}
    ).ToList();

const int Size = 32;
Action<int> handler = threadnr => {
    Console.WriteLine(threadnr + " => " + Thread.CurrentThread.ManagedThreadId);
    for (int i = 0; i < 10000; i++)    {
        var wb = new WriteableBitmap(Size, Size, 96, 96, PixelFormats.Bgra32, null);
        wb.Lock();
        var stride = wb.BackBufferStride;
        var blocks = stride / sizeof(int);
        unsafe {
            var row = (byte*)wb.BackBuffer;
            for (int y = 0; y < wb.PixelHeight; y++, row += stride)
            {
                var start = (int*)row;
                for (int x = 0; x < blocks; x++, start++)
                    *start = i;
            }
        }
        wb.Unlock();
        wb.Freeze();     }
};
var sw = Stopwatch.StartNew();
Console.WriteLine("start: {0:n3} ms", sw.Elapsed.TotalMilliseconds);
Parallel.For(0, Environment.ProcessorCount, new ParallelOptions{MaxDegreeOfParallelism = Environment.ProcessorCount}, handler);
Console.WriteLine("stop : {0:n2} s", sw.Elapsed.TotalSeconds);

GC.KeepAlive(objectCountPressure);


我可以使用“ EntityFramework”多次运行此测试:它总是在〜1.5s内返回,并且“#Induced GC”有时会增加1或2。

当我将“ const int Size = 48”更改为“ const int Size = 48”时,发生了非常非常糟糕的事情:“#诱导GC”每秒增加10次,现在整个运行时间超过一分钟:〜80秒!
[在Win7x64 Core-i7-2600上测试,带有8GB RAM // .NET 4.0.30319.237]

WTF !?

框架有一个非常严重的错误,或者我做的是完全错误的事情。

顺便说一句:
我不是通过图像处理来解决这个问题的,而只是通过使用包含通过DataTemplate对某些数据库实体的Image的工具提示来解决这个问题:
当RAM中没有太多对象时,此方法运行良好(快速),但是当存在数百万个其他对象(完全不相关)时,则显示工具提示始终会延迟几秒钟,而其他所有情况都很好。

最佳答案

在所有SafeMILHandleMemoryPressureSafeMILHandle废话之下,是对MS.Internal.MemoryPressure上方法的调用,该方法使用静态字段“ _totalMemory”来跟踪WPF认为分配了多少内存。当达到(相当小的)限制时,诱导的GC将开始并且永远不会结束。

您可以使用一点反射魔术就完全停止WPF的这种行为。只需将_totalMemory设置为适当的负数,这样就永远不会达到限制,并且永远不会发生诱导的GC:

typeof(BitmapImage).Assembly.GetType("MS.Internal.MemoryPressure")
    .GetField("_totalMemory", BindingFlags.NonPublic | BindingFlags.Static)
    .SetValue(null, Int64.MinValue / 2);

关于.net - 处理小图像(<= 4k像素数据)时是否强制使用GC?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7331735/

10-15 05:31