Мой код
public static class Canal
{
public static List<byte> A = new List<byte>();
public static List<byte> R = new List<byte>();
public static List<byte> G = new List<byte>();
public static List<byte> B = new List<byte>();
}
public static void Load()
{
using (var fs = new FileStream("Canal_A.txt", FileMode.Open))
{
var array = new byte[(int)fs.Length];
fs.Read(array, 0, (int)fs.Length);
Canal.A.AddRange(array);
}
using (var fs = new FileStream("Canal_R.txt", FileMode.Open))
{
var array = new byte[(int)fs.Length];
fs.Read(array, 0, (int)fs.Length);
Canal.R.AddRange(array);
}
using (var fs = new FileStream("Canal_G.txt", FileMode.Open))
{
var array = new byte[(int)fs.Length];
fs.Read(array, 0, (int)fs.Length);
Canal.G.AddRange(array);
}
using (var fs = new FileStream("Canal_B.txt", FileMode.Open))
{
var array = new byte[(int)fs.Length];
fs.Read(array, 0, (int)fs.Length);
Canal.B.AddRange(array);
}
}
public void F()
{
var color = new List<Color>();
for (int i = 0; i <Canal.A.Count; i++)
{
color.Add(Color.FromArgb(Canal.A[i], Color.FromArgb(Canal.R[i], Canal.G[i], Canal.B[i])));
}
}
У меня в файлах раздельно хранится ARGB каналы картинки. Я считываю все каналы, потом создаю из них цвета, затем из цветов делаю картинку. Все работает. Но когда я вызываю F()
то цикл отжерает около 1 Гб оперативки, в зависимости от размера картинки, и при этом память не освобождается после отработки функции. Как результат каждый вызов функции + 1 Гб занятой оперативы(( Как это можно оптимизировать? Я так понял что память отжерает из за того что цикл больше 10 мил раз отрабатует, но почему тогда после отработки память остается забитой?
Вот полная функция, больше программа не делает ничего.
public static void Decoder(string fileName)
{
var color = new List<Color>();
Load();
for (int i = 0; i < Canal.A.Count; i++)
{
color.Add(Color.FromArgb(Canal.A[i], Color.FromArgb(Canal.R[i], Canal.G[i], Canal.B[i])));
}
Console.WriteLine(".....");
using (var bmp = new Bitmap(fileName))
{
int counter = 0;
for (int i = 0; i < bmp.Height; i++)
{
for (int j = 0; j < bmp.Width; j++)
{
bmp.SetPixel(j, i, color[counter]);
counter++;
}
}
bmp.Save($"_{fileName}");
}
color.Clear();
Console.WriteLine("FINISH");
}
На сколько я знаю, статические классы сборщик мусора не забирает, т.к. фактически они не являются объектами и не потребляют память. НО статические поля статического класса - уже являются объектами и хранятся в памяти и не будут собраны GC, потому что будут доступны в течение всего жизненного цикла приложения. В вашем случае, можно попытаться принудительно присвоить значение null
полям класса Canal
: (A,R,G,B), чтобы они стали доступны для GC.
У вас в Decoder вызывается функция Load, заполняющая листы каналов, но при этом ни где не происходит очистка каналов => память закономерно будет утекать, т.к. листы каналов будут постоянно увеличиваться.
Добавьте предварительную очистку каналов, например так:
...
using (var fs = new FileStream("Canal_A.txt", FileMode.Open))
{
Canal.A.Clear();
var array = new byte[fs.Length];
fs.Read(array, 0, (int)fs.Length);
Canal.A.AddRange(array);
}
...
для каждого соответственно. При каждой следующей загрузке данных, предыдущие будут гарантировано выгружены и, позже, съедены GC. Если скорость реакции GC будет маловата, а данных очень много, то можно его принудительного пнуть с помощью GC.Collect()
. Только не нужно трогать GC при малом объеме данных, это ни чего не даст кроме ухудшения производительности.
Еще можно модифицировать ваш класс с каналами
public static class Canal
{
public static byte[] A;
public static byte[] R;
public static byte[] G;
public static byte[] B;
}
Тогда заполнение делать так:
public static void Load()
{
Canal.A = File.ReadAllBytes("Canal_A.txt");
Canal.R = File.ReadAllBytes("Canal_R.txt");
Canal.G = File.ReadAllBytes("Canal_G.txt");
Canal.B = File.ReadAllBytes("Canal_B.txt");
}
Тут очистка не требуется, т.к. мы каждый раз создаем канал заново. Ручную работу с потоком заменил на готовое решение фреймворка, раз уж вы вычитываете файлы целиком. Ручная работа с потоком была бы полезна при поточной обработке файлов без полной загрузки их в память, а в вашем варианте просто еще одно место возможной ошибки.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
У меня есть например класс-наследник от ListViewItem - AdvancedListViewItemВ XAML я могу задать
По какой причине метод InterlockedAdd принимает только int? Чем double мешает при атомарности?
При добавлении данных с помощью GridViewDataRowInfo в цикле, добавляется только последняя запись в чём может быть проблема?
ВNET есть пул потоков, - это заготовленные потоки, готовые к выполнению какой-то задачи