Skip to content

Memory allocated by new mapnik.Image() doesn't seem to be freed by GC #950

Open

Description

@zdila

Our server is regularily killed by kernel because it eats all the RAM. It seems to be caused by not freeing unreferenced images created by new mapnik.Image(...);

Testcase:

for (let i = 0; i < 1000000; i++) {
  new mapnik.Image(256, 256);
}

Activity

  1. zdila commented on Jul 6, 2020

    @zdila
    ContributorAuthor

    I am not sure if this issue affects only image or other types, for example mapnik.Map, mapnik.Color. Also if image.resize() returns new image then maybe it is also never freed.

  2. changed the title [-]Memory allocated by new mapnik.Image() doesn't seems to be freed on GC[/-] [+]Memory allocated by new mapnik.Image() doesn't seem to be freed by GC[/+] on Jul 6, 2020
  3. springmeyer commented on Aug 8, 2020

    @springmeyer
    Member

    @zdila can you try the v4.5.1 release to see if it improves your memory usage? Based on my testing, it should.

  4. zdila commented on Aug 14, 2020

    @zdila
    ContributorAuthor

    @springmeyer I can reproduce the testcase also in version 4.5.2 (eats 16GB ram in 4 seconds and then starts to swap).

  5. artemp commented on Aug 14, 2020

    @artemp
    Member

    @zdila - This is not a memory leak but rather design issue/feature

    mapnik.Image is allocating external memory : https://github.com/mapnik/node-mapnik/blob/master/src/mapnik_image.cpp#L195 but GC is not aware of this. The way to inform GC about these allocations is to call Napi::MemoryManagement::AdjustExternalMemory(env, size); when image allocated and Napi::MemoryManagement::AdjustExternalMemory(env, -size); when finaliser is called. Those calls don't come for free, though.

    It's more efficient to do something like

    var mapnik = require('../');
    for (let i = 0; i < 1000000; i++) {
      new mapnik.Image(256, 256);
      if (i % 1000 == 0)
      {
        global.gc();
      }
    }
    

    and not call Napi::MemoryManagement::AdjustExternalMemory for ever new mapnik.Image(...) . I guess this was behind original motivation for this implementation.
    /cc @springmeyer

  6. zdila commented on Aug 14, 2020

    @zdila
    ContributorAuthor

    Thanks for the explanation. To prevent memory leaks we already implemented reusing mapnik.Image instances in our project.

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