我有一个Visual Studio c#app,其任务是下载图片,进行一些操作,如旋转和翻转,并将新图片存储在外部HD中。
我有几个线程做同样的工作。
当应用程序运行了几个小时后,会出现异常,表明存储内存不足。
下图显示了应用程序启动时的进程内存,但是当它运行一段时间后,这样的内存会增加到3Gb。
在程序中我关闭所有流,内存流,位图,实例等。 所以,问题是,如何在执行期间释放内存或避免内存增加?
try
{
request = (HttpWebRequest)WebRequest.Create(new Uri(this._url, UriKind.Absolute));
request.UserAgent = UserAgent.get_user_agent();
noCachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
request.CachePolicy = noCachePolicy;
response = request.GetResponse();
responseStream = response.GetResponseStream();
reader = new BinaryReader(responseStream);
memoryStream = new MemoryStream();
byte[] bytebuffer = new byte[BytesToRead];
int bytesRead = reader.Read(bytebuffer, 0, BytesToRead);
while (bytesRead > 0)
{
memoryStream.Write(bytebuffer, 0, bytesRead);
bytesRead = reader.Read(bytebuffer, 0, BytesToRead);
}
image.BeginInit();
memoryStream.Seek(0, SeekOrigin.Begin);
image.StreamSource = memoryStream;
image.EndInit();
if ( image.Width < 100 || image.Height < 50 )
{
_parent.working_image = "Error procesado imagen";
_parent.isWorking = false;
return false;
}
Bitmap image_rotated = CropImage(RotateFlipImage(BitmapImage2Bitmap(image)));
if (image_rotated == null)
{
_parent.working_image = "Error procesado imagen";
_parent.isWorking = false;
return false;
}
BitmapFrame image200 = CreateResizedImage(Bitmap2BitmapImage(image_rotated), "large");
BitmapFrame image100 = CreateResizedImage(Bitmap2BitmapImage(image_rotated), "short");
// Directorio
int directory_main = (int)(this._Id / 10000);
// Generamos la imagen de 200px
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
String photolocation = @"D:\hilo_" + hilo + "_200.jpg"; //file name
encoder.Frames.Add(BitmapFrame.Create(image200));
FileStream filestream = null;
try
{
using (filestream = new FileStream(photolocation, FileMode.Create))
{
encoder.Save(filestream);
}
// creamos directorio si no existe
System.IO.Directory.CreateDirectory(@"D:\backoffice\originales\" + directory_main + @"\" + this._Id);
if (!this.saveImage(photolocation, @"D:\backoffice\originales\" + directory_main + @"\" + this._Id + @"\" + _filename + "_200.jpg"))
{
_parent.working_image = "Error procesado imagen";
_parent.isWorking = false;
image = null;
memoryStream.Close();
filestream.Close();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
return false;
}
filestream.Close();
// Generamos la imagen de 100px
encoder = new JpegBitmapEncoder();
photolocation = @"D:\hilo_" + hilo + "_100.jpg"; //file name
encoder.Frames.Add(BitmapFrame.Create(image100));
using (filestream = new FileStream(photolocation, FileMode.Create))
{
encoder.Save(filestream);
}
// creamos directorio si no existe
if (!this.saveImage(photolocation, @"D:\backoffice\originales\" + directory_main + @"\" + this._Id + @"\" + _filename + "_100.jpg"))
{
_parent.working_image = "Error procesado imagen";
_parent.isWorking = false;
image = null;
memoryStream.Close();
filestream.Close();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
return false;
}
filestream.Close();
encoder = null;
image100 = null;
image200 = null;
SqlConnection con = new SqlConnection(@"Data Source=DESKTOP-UC7AQ3V\SQLEXPRESS;Integrated Security=SSPI;User ID=frank;password=jungla");
SqlCommand cmd = new SqlCommand("UPDATE dbo.image_objects_download_log SET locked=0, worked=1, isWorking=1 WHERE object_id=@id", con);
cmd.Parameters.AddWithValue("@id", Id);
con.Open();
cmd.ExecuteNonQuery();
cmd.Dispose();
con.Close();
_parent.working_image = "Trabajo finalizado con éxito";
_parent.isWorking = false;
image = null;
memoryStream.Close();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
return true;
}
catch (IOException e)
{
Console.WriteLine("---------> " + e.Message);
_parent.working_image = "Error procesado imagen";
_parent.isWorking = false;
image = null;
memoryStream.Close();
filestream.Close();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
return false;
}
catch (UriFormatException e)
{
_parent.working_image = "Error procesado imagen";
_parent.isWorking = false;
image = null;
memoryStream.Close();
filestream.Close();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
return false;
}
}
答案 0 :(得分:2)
我建议您在IDisposable
块中包含实现using
的所有对象。我将在代码的响应部分演示:
try
{
request = (HttpWebRequest)WebRequest.Create(new Uri(this._url, UriKind.Absolute));
request.UserAgent = UserAgent.get_user_agent();
noCachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
request.CachePolicy = noCachePolicy;
(WebResponse response = request.GetResponse())
{
// Rest of your code inside here
}
}
这对您使用的图像资源尤为重要。
BitmapFrame image200 = null;
BitmapFrame image100 = null;
using(Bitmap image_rotated = CropImage(RotateFlipImage(BitmapImage2Bitmap(image))))
{
if (image_rotated == null)
{
_parent.working_image = "Error procesado imagen";
_parent.isWorking = false;
return false;
}
image200 = CreateResizedImage(Bitmap2BitmapImage(image_rotated), "large");
image100 = CreateResizedImage(Bitmap2BitmapImage(image_rotated), "short");
}
您还应该检查方法Bitmap2BitmapImage
答案 1 :(得分:1)
您没有丢弃位图,BitmapFrame或图像。我不确定你在哪里创建你的图像,但我建议你在本地创建它 - 所以它可以在你完成处理后在本地处理。
在Using语句中包装本地创建的位图和图像,该语句将在执行后立即处理对象。这个问题有关于此的更多细节
Right way to dispose Image/Bitmap and PictureBox
或
您还可以在图像对象上调用Dispose()。尝试在本地创建图像并在完成后将其丢弃。
使用Finalize()方法清理BitmapFrame。
的资源您也可以在图像对象上调用Dispose。尝试在本地创建图像并在完成后将其丢弃。