qnanopainter icon indicating copy to clipboard operation
qnanopainter copied to clipboard

Possible memory leak

Open miguelangelorenes opened this issue 6 years ago • 3 comments

I am writing a QQuick 2.0 application based on qnanopainter with QNANO_USE_RENDERNODE activated. I have a custom QNanoQuickItem that is returning on "createItemPainter" method a custom QNanoQuickItemPainter that basically do this on "paint" method:

painter()->beginPath();
painter()->moveTo(x, y);
painter()->quadTo(x1, y1);
painter()->stroke();

The result is very fine and I am getting a high performance.

Also I am creating several custom QNanoQuickItem (all the creation actions are made in C++) and I can make actions over them separately:

  • move
  • transform
  • delete

The point is I can see that the application is not releasing the memory once I delete my custom QNanoQuickItem. I am checking the destructors on my clases and everything is ok. I am using "Visual Leak Detector"(VLD) to try to detect the leak and all is pointing to the application is leaking/accumulating memory on qnanopainter side. VLD report is telling the memory allocated/reallocated on glnvg__allocFragUniforms/glnvg__allocVerts/glnvg__renderStroke/nvg__allocTempVerts is never released.

So, the behavior I can see is:

  • Inc the use of memory when creating items: That is more than ok
  • The memory is not released when erasing created items

Until now, reading qnanopainter code and tracing it, it looks like the library is accumulating memory for render tasks on QNanoPainter instance.

Is there something I can do to release that memory? I am over loading qnanopainter solution?

miguelangelorenes avatar Jul 31 '18 08:07 miguelangelorenes

There is an easy way to test QNanoQuickItem create/release in examples/gallery/qnanopainter_features by uncommenting lines 42-61 in main.qml. This makes gallery to automatically scroll between views and causes item constructor & destructor, you can confirm this by adding debug prints into galleryitem.cpp

Running it for longer time I see memory slightly growing, but then dropping back down after every few minutes likely due to Qt Quick engine caching. Tested now on Windows + Qt 5.10.0, with and without QNANO_USE_RENDERNODE and memory consumption remains at ~50Mb.

gallery_autoscroll_memory_usage

Please test and report if you see memory usage growing over time + the system you are using.

QUItCoding avatar Jul 31 '18 11:07 QUItCoding

You are right, the amount of memory is not too much and also it is stable in the qnanopainter_features example but, if you press on "<" button to go back the Gallery main screen, the memory used on qnanopainter_features is not released.

By other hand, I added a little trace on nanovg.c nvg__allocTempVerts:

printf("%d %d %d\n", ctx, ctx->cache->cverts, nverts);
fflush(stdout);

And the gallery example cache->cverts is 1280 all the time. But on my aplication, it is ~22000 when making medium-long drawing(path created with ~1700 points) on a maximized windows 1080p, and for sure, the figures are biggers on a 4K screen.

I am making some experiment and with this change:

QNanoQuickItemPainter::QNanoQuickItemPainter()
     : m_window(nullptr)
    , m_painter(new QNanoPainter)
     , m_fillColor(0.0, 0.0, 0.0, 0.0)
     , m_viewWidth(0)
     , m_viewHeight(0)
 
 QNanoQuickItemPainter::~QNanoQuickItemPainter()
 {
    delete m_painter;
 }

That means, a QNanoPainter for each item. The memory is released each time I delete a QNanoQuickItemPainter and the aplication looks like stable. Just a performance issue when triying to create 'n' QNanoQuickItem at the same time because of 'n' painter are created. Currently thinking on how resolve this.

So, my worries is about how will affect to the performance.

Could you recommend me anything?

miguelangelorenes avatar Jul 31 '18 13:07 miguelangelorenes

As you said, your change would create own QNanoPainter for every QNanoQuickItemPainter which increases item construction time and total memory usage. Implementation currently uses Q_GLOBAL_STATIC to share QNanoPainter instance for all QNanoQuickItemPainters. That also means that this single QNanoPainter instance is not released until application exits, but that shouldn't harm anything.

Maybe your specific usage causes memory leaking, don't know without more details. But also I think generally (re)creating big amount of QNanoQuickItems (or any QQuickItems) should be avoided... My approach has been single QNanoQuickItem which then manages and renders multiple "items", for maximum performance and freedom. What kind of software are you working on, wouldn't that approach work for you?

QUItCoding avatar Jul 31 '18 19:07 QUItCoding