Skip to content

Possible Memory leak? #123

Closed
Closed

Description

@Daniele122898

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

I have send my code to many ppl on many Discords and everybody says that it is not my code at fault and that it probably is something else. So here i am.
In the SetBG function i use the ImageSharp resize command to resize the image. When i do this my Ram usage rockets from 30mb to 70mb. So i made a snapshot and checked the heap and ImageSharp is using a ton of ram for no apparent reason. Even after a very long time not even the GC removes it.

I tried alot of stuff. I dispose and flush everything and even desperately tried to call the GC at the bottom. Nothing seems to work

https://hastebin.com/xuyiriqunu.cs

Steps to Reproduce

Well you see the entire source code and the functions i use..

System Configuration

  • ImageSharp version: v.1.0.0-alpha2-00118
  • Other ImageSharp packages and versions:
    ImageSharp drrawing, gif, jpeg, png, processing all same version besides processing (00106) and format.png(00114)
  • Environment (Operating system, version and so on): Windows 10 Pro 10.0.14393 Build 14393
  • .NET Framework version: .NET core 1.0.1
  • Additional information: Also using CoreCompat.System.Drawing.

Activity

  1. dlemstra commented on Mar 5, 2017

    @dlemstra
    Member

    You are not disposing the image instances that you create. And I would advise you to reduce your code to a smaller sample that demonstrates we are not cleaning up memory properly. Your code example is way to big for us now.

  2. Daniele122898 commented on Mar 5, 2017

    @Daniele122898
    Author

    ´

                Configuration.Default.AddImageFormat(new PngFormat());
    
                using (var input = File.OpenRead($"{Context.User.Username}#{Context.User.Discriminator}BG.jpg"))
                {
                    using (var output = File.OpenWrite($"{Context.User.Username}#{Context.User.Discriminator}BGF.jpg"))
                    {
                        var image = new ImageSharp.Image(input);
                        //int divide = image.Width / 900;
                        //int width = image.Width / divide;
                        //int height = image.Height / divide;
                        image.Resize(new ResizeOptions
                        {
                            Size = new ImageSharp.Size(900, 10000),
                            Mode = ResizeMode.Max
                        });
                        //image.ExifProfile = null; TODO FIX THIS
                        //image.Quality = quality;
                        image.Save(output);
                        image.Dispose();
                        await input.FlushAsync();
                        input.Dispose();
                        await output.FlushAsync();
                        output.Dispose();
    
                        /*.Resize(new ResizeOptions
                            {
                                Size = new ImageSharp.Size(size, size),
                                Mode = ResizeMode.Max
                            });*/
                    }
                }
                //IMAGE RESIZE END
                if (File.Exists($"{Context.User.Username}#{Context.User.Discriminator}BG.jpg"))
                {
                    File.Delete($"{Context.User.Username}#{Context.User.Discriminator}BG.jpg");
                }
    
    
                if (userBG.ContainsKey(Context.User.Id))
                {
                }
                else
                {
                    userBG.TryAdd(Context.User.Id, true);
                }
    
                GC.Collect(); //TODO Change this system
    
                await Context.Channel.SendMessageAsync(":white_check_mark: Successfully set new BG!");
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                await SentryService.SendError(e, Context);
            }
        }`
    

    Oh sorry. Thats the important one. But im calling image.Dispose(); right after i saved it

  3. antonfirsov commented on Mar 5, 2017

    @antonfirsov
    Member

    Using a using block would be much safer, than calling .Dispose() manually.

    I don't think we can reproduce your scenario from the sample above. If you are 100% sure ImageSharp-s code is leaking, it must be do so in a simple, short, standalone console application too. That would be very helpful, and definitely a thing we should investigate.

  4. Daniele122898 commented on Mar 5, 2017

    @Daniele122898
    Author

    okey i will try to do that and post it in here then

    I just saw that imagesharp was the one in the Heap that was HUGE. That's why i thought that.

    But yes i'll try to do it in a smaller scale

  5. tocsoft commented on Mar 5, 2017

    @tocsoft
    Member

    Have you tried performing it in a loop to see if the memory keeps growing or just grows once and doesn't release?

  6. Daniele122898 commented on Mar 5, 2017

    @Daniele122898
    Author

    It's in a Discord bot so i just ran the command on different pics and different users and the ram usage only goes up once rly crazy. Like said from like 30mb to 70mb. Then when i run the command again it rises only by small amounts, usually around 4-8 mb.
    So it's mostly the first time the command get's run that the ram usage increases like crazy

  7. tocsoft commented on Mar 5, 2017

    @tocsoft
    Member

    Sounds like its our use of an array pool for storing the image data... Basically the memory will be reused for the next image and should only grow the once.

  8. Daniele122898 commented on Mar 5, 2017

    @Daniele122898
    Author

    http://prntscr.com/egarm9

    Seems like it when i look at the heap snapshot

  9. antonfirsov commented on Mar 5, 2017

    @antonfirsov
    Member

    I think @tocsoft is right, it works as expected. The arrays managed by ArrayPool are being reused if you create images with same, or smaller sizes. We do this to avoid allocation overhead and LOH fragmentation

    If the "leaked memory" stops growing after the application is warmed up, I think you have nothing to be worried about.

  10. Daniele122898 commented on Mar 6, 2017

    @Daniele122898
    Author

    that makes sense. So not having to reallocate the memory makes processing faster i assumse.

    Shall i close this issue then?

  11. dlemstra commented on Mar 6, 2017

    @dlemstra
    Member

    I am now wondering if we should add a configuration setting where the user can enable or disable array pooling. Some systems might need the memory returned after usage.

  12. JimBobSquarePants commented on Mar 6, 2017

    @JimBobSquarePants
    Member

    There's talk of the whole memory management thing pluggable.

  13. JimBobSquarePants commented on Mar 6, 2017

    @JimBobSquarePants
    Member

    But yeah, close this. The behaviour is expected. ArrayPool<T> pulls a minimum of then reuses which is beneficial in most circumstances.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions