Счетчик производительности «# Industed GC» (который должен оставаться на нулевом уровне в совершенном приложении) быстро увеличивается при обработке небольших файлов (< = 32x32) через WriteureBitmap
.
Хотя это не является существенным узким местом в небольшом приложении, это становится очень серьезной проблемой (замораживание приложения на 99,75% «% времени в GC» в течение нескольких секунд на каждом шаге), когда в памяти находится несколько тысяч объектов (например, контекст 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 и «# Industed GC» иногда увеличивается на 1 или 2.
Когда я меняю « const int Size = 48
» на « const int Size = 32
», происходит что-то очень плохое: «# Industed GC» увеличивается на 10 в секунду, и общая продолжительность выполнения теперь больше минуты: ~ 80!
[Протестировано на Win7x64 Core-i7-2600 с помощью 8GB RAM//.NET 4,0,30319,237]
WTF!?
Либо у Рамки очень плохая ошибка, либо я делаю что-то совершенно неправильно.
BTW :
Я обошел эту проблему, не выполняя обработку изображений, а просто используя подсказку, содержащую изображение для некоторых сущностей базы данных через DataTemplate:
Это работало хорошо (быстро), хотя в оперативной памяти не было очень много объектов, но когда существовало несколько миллионов других объектов (совершенно не связанных), то отображение всплывающей подсказки всегда задерживалось на несколько секунд, в то время как все остальное просто работало нормально.
Следующая инструкция завершается неуспешно с StartReferureException
:
TypeModel.Create().DeepClone(new string[1]);
Проверка исходного кода показывает, что исключение инициируется специально, подразумевая, что значения null
в массиве нарушают спецификацию буферов протокола (имеет смысл, null
не является повторением какого-либо значения).
Хорошо, спецификация правильная, но что нам делать, если в коллекции все еще есть нулевое значение? Есть ли решение, кроме того, чтобы убедиться, что значения null
никогда не ползуют в наши коллекции?
Спасибо.