简体   繁体   English

内存不足,使用进程

[英]Out Of Memory using Process

Ok, so I know I should be using the ImageMagick DLL... and I'm learning, testing, and working up to doing that. 好的,所以我知道我应该使用ImageMagick DLL ...,我正在学习,测试并正在努力做到这一点。 But in the mean time I'm using the inefficient method of calling Imagemagick's convert.exe via a process. 但是与此同时,我正在使用通过进程调用Imagemagick的convert.exe的低效方法。

It works fine with hundreds of images when I'm testing. 测试时,它可以处理数百张图像。 But then I move my WindowsForms program to a faster machine and it crashes every time at the same point. 但是之后,我将WindowsForms程序移到了更快的计算机上,并且每次都在同一时间崩溃。

It's a two step Process call. 这是一个两步流程调用。 The first time loop through all the files and produce the PNGs. 第一次遍历所有文件并生成PNG。 Then I loop through all the PNGs and composite it with a background and output a JPG. 然后,我遍历所有PNG并将其与背景合成并输出JPG。 But EVERY time at exactly 22 images it errors "System.OutOfMemoryException: Out of memory." 但是,每当精确到22张图像时,它都会出现错误“ System.OutOfMemoryException:内存不足”。 Is there something that is filling up that I need to kill or something? 是否有我需要杀死的东西正在填充?

    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();
        }

At first glance, you are using Image.FromFile twice in makeJPG() and not disposing the objects. 乍一看,您在makeJPG()两次使用了Image.FromFile ,而不处理对象。 Image.FromFile will usually create unmanaged GDI+ handles that need to be disposed. Image.FromFile通常将创建需要处理的非托管GDI +句柄。

From the documentation : 文档中

The file remains locked until the Image is disposed. 该文件将保持锁定,直到处理完映像为止。

So at first glance I'd assume you are just loading too much images in memory, and I'd try: 因此,乍一看,我假设您只是在内存中加载了太多图像,所以我尝试:

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();
  }
}

Since you are actually not using the images (just getting their height), you could make those using blocks smaller, but I'll leave that to you. 由于您实际上并未使用图像(只是获取图像的高度),因此可以使using块的图像更小,但我将留给您使用。

... but ... ...但是...

About the OutOfMemoryException 关于OutOfMemoryException

Also, you say it happens EXACTLY at 22 images (which would be weird for getting out of memory, unless the images are consistently big), but reading the same documentation: 另外,您说它恰好发生在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. 如果文件没有有效的图像格式,或者GDI +不支持文件的像素格式,则此方法将引发OutOfMemoryException异常。

So make sure the 22nd image (either the "source" or the "background", depending on where it throws) has a correct format 因此,请确保第22张图片(“来源”或“背景”,取决于它抛出的位置)的格式正确

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM