Я вижу счетчик производительности "# Induced GC" (который должен оставаться на нуле в идеальном приложении) быстро растет при обработке небольших файлов (< = 32x32) через WriteableBitmap
.
Хотя это небольшое препятствие внутри небольшого приложения, это становится очень большой проблемой (приложение замораживается при 99,75% "% времени в GC" в течение нескольких секунд на каждом шаге), когда в памяти имеется около тысячи объектов ( ex: EntityFramework
контекст, загруженный многими объектами и отношениями).
Синтетический тест:
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);
Я могу запустить этот тест, используя "const int Size = 48
" десяток раз: он всегда возвращается в ~ 1.5s, а "# Induced GC" иногда увеличивается на 1 или 2.
Когда я меняю "const int Size = 48
" на "const int Size = 32
", происходит что-то очень очень плохое: "# Induced GC" увеличивается на 10 в секунду, а общая продолжительность выполнения составляет более минуты: ~ 80 с!
[Протестировано на Win7x64 Core-i7-2600 с оперативной памятью 8 ГБ //.NET 4.0.30319.237]
WTF!?
Либо Framework имеет очень плохую ошибку, либо я делаю что-то совершенно неправильное.
BTW:
Я столкнулся с этой проблемой не с помощью обработки изображений, а просто с помощью всплывающей подсказки, содержащей изображение с некоторыми объектами базы данных через DataTemplate:
Это работало отлично (быстро), в то время как в ОЗУ не было очень много объектов, но когда существовало несколько миллионов других объектов (совершенно не связанных), то показывая подсказку, всегда задерживалась на несколько секунд, а все остальное просто отлично работало.