ilija veselica
ilija veselica

Reputation: 9574

How to detect a memory leak

I have doubts that this part of code causes memory leak:

    public FileResult ShowCroppedImage(int id, int size)
    {
        string path = "~/Uploads/Photos/";
        string sourceFile = Server.MapPath(path) + id + ".jpg";

        MemoryStream stream = new MemoryStream();
        var bitmap = imageManipulation.CropImage(sourceFile, size, size);
        bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
        Byte[] bytes = stream.ToArray();
        return File(bytes, "image/png");
    }

How could I make a test to see if this piece of code is the cause?

EDIT:

public Image CropImage(string sourceFile, int newWidth, int newHeight)
        {
            Image img = Image.FromFile(sourceFile); 
            Image outimage;

            int sizeX = newWidth;
            int sizeY = newHeight;

            MemoryStream mm = null;

            double ratio = 0;
            int fromX = 0;
            int fromY = 0;

            if (img.Width < img.Height)
            {
                ratio = img.Width / (double)img.Height;
                newHeight = (int)(newHeight / ratio);
                fromY = (img.Height - img.Width) / 2;
            }
            else
            {
                ratio = img.Height / (double)img.Width;
                newWidth = (int)(newWidth / ratio);
                fromX = (img.Width - img.Height) / 2;
            }
            if (img.Width == img.Height)
                fromX = 0;

            Bitmap result = new Bitmap(sizeX, sizeY);

            //use a graphics object to draw the resized image into the bitmap 
            Graphics grPhoto = Graphics.FromImage(result);

            //set the resize quality modes to high quality 
            grPhoto.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            grPhoto.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            //draw the image into the target bitmap 
            //now do the crop            
            grPhoto.DrawImage(
                img,
                new System.Drawing.Rectangle(0, 0, newWidth, newHeight),
                new System.Drawing.Rectangle(fromX, fromY, img.Width, img.Height),
                System.Drawing.GraphicsUnit.Pixel);


            // Save out to memory and get an image from it to send back out the method.
            mm = new MemoryStream();
            result.Save(mm, System.Drawing.Imaging.ImageFormat.Jpeg);
            img.Dispose();
            result.Dispose();
            grPhoto.Dispose();
            outimage = Image.FromStream(mm);

            return outimage;
        }

Upvotes: 0

Views: 1179

Answers (3)

DamienG
DamienG

Reputation: 6665

Given the question was how to detect memory leaks/usage, I'd recommend writing a method that calls your function recording the memory usage before and after:

public void SomeTestMethod()
{
    var before = System.GC.GetTotalMemory(false);
    // call your method
    var used = before - System.GC.GetTotalMemory(false);
    var unreclaimed = before - System.GC.GetTotalMemory(true);
}

Before will measure the memory usage before your function runs. The used variable will hold how much memory your function used before the garbage collector was run and unreclaimed will tell you how many bytes your function used even after trying to clean up your objects.

I suspect used will be high and unreclaimed will not - putting a using around your memory stream as the other posters suggest should make them closer although bear in mind you still have a byte array holding on to memory.

Upvotes: 0

L.B
L.B

Reputation: 116108

I would write it as

public FileResult ShowCroppedImage(int id, int size)
{
    string path = "~/Uploads/Photos/";
    string sourceFile = Server.MapPath(path) + id + ".jpg";

    using (MemoryStream stream = new MemoryStream())
    {
        using (Bitmap bitmap = imageManipulation.CropImage(sourceFile, size, size))
        {
            bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
            Byte[] bytes = stream.ToArray();
            return File(bytes, "image/png");
        }
    }
}

to ensure that stream.Dispose & bitmap.Dispose are called.

Upvotes: 3

Travis J
Travis J

Reputation: 82267

Might want to call stream.dispose(); after Byte[] bytes = stream.ToArray();.

Upvotes: 0

Related Questions