使用进程内存不足
Out Of Memory using Process
好的,所以我 知道 我应该使用 ImageMagick DLL...我正在学习、测试和努力做到这一点。但与此同时,我正在使用通过进程调用 Imagemagick convert.exe 的低效方法。
当我测试时,它可以很好地处理数百张图像。但是后来我将我的 WindowsForms 程序移到一台更快的机器上,它每次都在同一点崩溃。
这是一个两步流程调用。第一次遍历所有文件并生成 PNG。然后我遍历所有 PNG 并将其与背景合成并输出 JPG。但是每次恰好 22 张图像时它都会出错 "System.OutOfMemoryException: Out of memory." 是否有什么东西正在填充我需要杀死什么?
foreach (string file in files)
{
try
{
string captureImg = Path.GetFileName(file);
string maskImg = file.Replace("X.JPG", "Y.JPG");
string OutputImage = string.Format("{0}.png", Path.GetFileNameWithoutExtension(captureImg));
string output = Path.Combine(destFolder, OutputImage);
//MessageBox.Show(output);
progressBarImage.Value = progressBarImage.Value + 1;
lblStatus.Text = string.Format("Image {0} of {1}", progressBarImage.Value, maxFiles);
makePNG(file, maskImg, output);
Application.DoEvents();
}
catch (Exception)
{
}
}
if (chkBG.Checked)
{
//try
//{
string JPGdir = Path.Combine(destFolder, "JPGs");
string[] PNGfiles = Directory.GetFiles(destFolder, "*C.PNG");
lblProgress.Text = "Generating JPGs with Background";
progressBarImage.Value = 0;
progressBarImage.Maximum = files.Length;
message = "PNG and JPG Export Complete";
if (!Directory.Exists(JPGdir))
{
Directory.CreateDirectory(JPGdir);
}
foreach (string PNGfile in PNGfiles)
{
Application.DoEvents();
string outputJPG = string.Format("{0}.jpg", Path.GetFileNameWithoutExtension(PNGfile));
string result = Path.Combine(JPGdir, outputJPG);
progressBarImage.Value += 1;
lblStatus.Text = string.Format("Image {0} of {1}", progressBarImage.Value, files.Length);
makeJPG(PNGfile, txtBackground.Text, result);
//MessageBox.Show(PNGfile);
}
private void makePNG(string source, string mask, string output)
{
if (!source.EndsWith("Y.JPG"))
{
Process proc = new Process();
string appPath = Path.GetDirectoryName(Application.ExecutablePath);
proc.EnableRaisingEvents = false;
proc.StartInfo.FileName = @"""C:\Program Files\ImageMagick-6.9.0-Q16\convert.exe""";
proc.StartInfo.Arguments = string.Format(@"{0} {1} -alpha off -compose copy-opacity -level 5% -composite {2}", source, mask, output);
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
proc.WaitForExit();
}
}
private void makeJPG(string source, string background, string output)
{
float BGimg = Image.FromFile(background).Height;
float SubjectImg = Image.FromFile(source).Height;
float ResultHeight = 100 * (BGimg / SubjectImg);
int Height = Convert.ToInt32(ResultHeight);
Process procJPG = new Process();
string appPath = Path.GetDirectoryName(Application.ExecutablePath);
procJPG.EnableRaisingEvents = false;
procJPG.StartInfo.FileName = @"""C:\Program Files\ImageMagick-6.9.0-Q16\convert.exe""";
procJPG.StartInfo.Arguments = string.Format(@"{1} ( {0} -resize {3}% ) -gravity South -composite {2}", source, background, output, Height);
procJPG.StartInfo.UseShellExecute = false;
procJPG.StartInfo.RedirectStandardOutput = true;
procJPG.StartInfo.CreateNoWindow = true;
procJPG.Start();
procJPG.WaitForExit();
}
乍一看,您在 makeJPG()
中使用了 Image.FromFile
两次,并且没有释放对象。 Image.FromFile
通常会创建需要释放的非托管 GDI+ 句柄。
The file remains locked until the Image is disposed.
所以乍一看我会假设你只是在内存中加载了太多图像,我会尝试:
private void makeJPG(string source, string background, string output)
{
using(var backgroundImg = Image.FromFile(background))
using(var sourceImg = Image.FromFile(source))
{
float BGimg = backgroundImg.Height;
float SubjectImg = sourceImg.Height;
float ResultHeight = 100 * (BGimg / SubjectImg);
int Height = Convert.ToInt32(ResultHeight);
Process procJPG = new Process();
string appPath = Path.GetDirectoryName(Application.ExecutablePath);
procJPG.EnableRaisingEvents = false;
procJPG.StartInfo.FileName = @"""C:\Program Files\ImageMagick-6.9.0-Q16\convert.exe""";
procJPG.StartInfo.Arguments = string.Format(@"{1} ( {0} -resize {3}% ) -gravity South -composite {2}", source, background, output, Height);
procJPG.StartInfo.UseShellExecute = false;
procJPG.StartInfo.RedirectStandardOutput = true;
procJPG.StartInfo.CreateNoWindow = true;
procJPG.Start();
procJPG.WaitForExit();
}
}
由于您实际上并没有使用图像(只是获取它们的高度),您可以将这些 using
块变小,但我会留给你。
...但是...
关于 OutOfMemoryException
此外,您说它恰好发生在 22 张图片上(如果内存不足会很奇怪,除非图片一直很大),但请阅读相同的文档:
If the file does not have a valid image format or if GDI+ does not support the pixel format of the file, this method throws an OutOfMemoryException exception.
因此请确保第 22 张图像("source" 或 "background",具体取决于它抛出的位置)具有正确的格式
好的,所以我 知道 我应该使用 ImageMagick DLL...我正在学习、测试和努力做到这一点。但与此同时,我正在使用通过进程调用 Imagemagick convert.exe 的低效方法。
当我测试时,它可以很好地处理数百张图像。但是后来我将我的 WindowsForms 程序移到一台更快的机器上,它每次都在同一点崩溃。
这是一个两步流程调用。第一次遍历所有文件并生成 PNG。然后我遍历所有 PNG 并将其与背景合成并输出 JPG。但是每次恰好 22 张图像时它都会出错 "System.OutOfMemoryException: Out of memory." 是否有什么东西正在填充我需要杀死什么?
foreach (string file in files)
{
try
{
string captureImg = Path.GetFileName(file);
string maskImg = file.Replace("X.JPG", "Y.JPG");
string OutputImage = string.Format("{0}.png", Path.GetFileNameWithoutExtension(captureImg));
string output = Path.Combine(destFolder, OutputImage);
//MessageBox.Show(output);
progressBarImage.Value = progressBarImage.Value + 1;
lblStatus.Text = string.Format("Image {0} of {1}", progressBarImage.Value, maxFiles);
makePNG(file, maskImg, output);
Application.DoEvents();
}
catch (Exception)
{
}
}
if (chkBG.Checked)
{
//try
//{
string JPGdir = Path.Combine(destFolder, "JPGs");
string[] PNGfiles = Directory.GetFiles(destFolder, "*C.PNG");
lblProgress.Text = "Generating JPGs with Background";
progressBarImage.Value = 0;
progressBarImage.Maximum = files.Length;
message = "PNG and JPG Export Complete";
if (!Directory.Exists(JPGdir))
{
Directory.CreateDirectory(JPGdir);
}
foreach (string PNGfile in PNGfiles)
{
Application.DoEvents();
string outputJPG = string.Format("{0}.jpg", Path.GetFileNameWithoutExtension(PNGfile));
string result = Path.Combine(JPGdir, outputJPG);
progressBarImage.Value += 1;
lblStatus.Text = string.Format("Image {0} of {1}", progressBarImage.Value, files.Length);
makeJPG(PNGfile, txtBackground.Text, result);
//MessageBox.Show(PNGfile);
}
private void makePNG(string source, string mask, string output)
{
if (!source.EndsWith("Y.JPG"))
{
Process proc = new Process();
string appPath = Path.GetDirectoryName(Application.ExecutablePath);
proc.EnableRaisingEvents = false;
proc.StartInfo.FileName = @"""C:\Program Files\ImageMagick-6.9.0-Q16\convert.exe""";
proc.StartInfo.Arguments = string.Format(@"{0} {1} -alpha off -compose copy-opacity -level 5% -composite {2}", source, mask, output);
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
proc.WaitForExit();
}
}
private void makeJPG(string source, string background, string output)
{
float BGimg = Image.FromFile(background).Height;
float SubjectImg = Image.FromFile(source).Height;
float ResultHeight = 100 * (BGimg / SubjectImg);
int Height = Convert.ToInt32(ResultHeight);
Process procJPG = new Process();
string appPath = Path.GetDirectoryName(Application.ExecutablePath);
procJPG.EnableRaisingEvents = false;
procJPG.StartInfo.FileName = @"""C:\Program Files\ImageMagick-6.9.0-Q16\convert.exe""";
procJPG.StartInfo.Arguments = string.Format(@"{1} ( {0} -resize {3}% ) -gravity South -composite {2}", source, background, output, Height);
procJPG.StartInfo.UseShellExecute = false;
procJPG.StartInfo.RedirectStandardOutput = true;
procJPG.StartInfo.CreateNoWindow = true;
procJPG.Start();
procJPG.WaitForExit();
}
乍一看,您在 makeJPG()
中使用了 Image.FromFile
两次,并且没有释放对象。 Image.FromFile
通常会创建需要释放的非托管 GDI+ 句柄。
The file remains locked until the Image is disposed.
所以乍一看我会假设你只是在内存中加载了太多图像,我会尝试:
private void makeJPG(string source, string background, string output)
{
using(var backgroundImg = Image.FromFile(background))
using(var sourceImg = Image.FromFile(source))
{
float BGimg = backgroundImg.Height;
float SubjectImg = sourceImg.Height;
float ResultHeight = 100 * (BGimg / SubjectImg);
int Height = Convert.ToInt32(ResultHeight);
Process procJPG = new Process();
string appPath = Path.GetDirectoryName(Application.ExecutablePath);
procJPG.EnableRaisingEvents = false;
procJPG.StartInfo.FileName = @"""C:\Program Files\ImageMagick-6.9.0-Q16\convert.exe""";
procJPG.StartInfo.Arguments = string.Format(@"{1} ( {0} -resize {3}% ) -gravity South -composite {2}", source, background, output, Height);
procJPG.StartInfo.UseShellExecute = false;
procJPG.StartInfo.RedirectStandardOutput = true;
procJPG.StartInfo.CreateNoWindow = true;
procJPG.Start();
procJPG.WaitForExit();
}
}
由于您实际上并没有使用图像(只是获取它们的高度),您可以将这些 using
块变小,但我会留给你。
...但是...
关于 OutOfMemoryException
此外,您说它恰好发生在 22 张图片上(如果内存不足会很奇怪,除非图片一直很大),但请阅读相同的文档:
If the file does not have a valid image format or if GDI+ does not support the pixel format of the file, this method throws an OutOfMemoryException exception.
因此请确保第 22 张图像("source" 或 "background",具体取决于它抛出的位置)具有正确的格式