vtkActor OpenGL resources remain in memory

I am experiencing memory bloating when rendering vtkActors in a QQuickFrameBufferObject::Renderer. VTK is version 8.1.1 and Qt is version 5.12.3.

It appears that every vtkActor’s texture and geometry remains in memory indefinitely. With a 1500x800 texture rendered 10 times per second, the memory increase is quite noticeable.

The valgrind caller stack appears to pass through libnvidia-glcore.so and libGLX_nvidia.so, so it might be a driver problem, but I want to see first if I am doing something wrong with how I am using VTK. Here is a capture of the few biggest memory leaks after terminating the program:

[Snip...]
    ==19601== 108,295,786 bytes in 366 blocks are possibly lost in loss record 23,199 of 23,201
    ==19601==    at 0x483774F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==19601==    by 0x1C296B28: ??? (in /usr/lib/x86_64-linux-gnu/libGLX_nvidia.so.390.116)
    ==19601==    by 0x1D75FD56: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D74AE0C: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D3A01C8: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D3A2765: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x6DCCFAD: vtkOpenGLBufferObject::UploadInternal(void const*, unsigned long, vtkOpenGLBufferObject::ObjectType) (vtkOpenGLBufferObject.cxx:149)
    ==19601==    by 0x6E6A6D5: bool vtkOpenGLBufferObject::Upload<float>(float const*, unsigned long, vtkOpenGLBufferObject::ObjectType) (vtkOpenGLBufferObject.h:142)
    ==19601==    by 0x6EA282B: vtkOpenGLVertexBufferObject::UploadDataArray(vtkDataArray*) (vtkOpenGLVertexBufferObject.cxx:368)
    ==19601==    by 0x6EAF32A: vtkOpenGLVertexBufferObjectGroup::BuildAllVBOs(vtkOpenGLVertexBufferObjectCache*) (vtkOpenGLVertexBufferObjectGroup.cxx:334)
    ==19601==    by 0x6E43EE8: vtkOpenGLPolyDataMapper::BuildBufferObjects(vtkRenderer*, vtkActor*) (vtkOpenGLPolyDataMapper.cxx:3203)
    ==19601==    by 0x6E415A9: vtkOpenGLPolyDataMapper::UpdateBufferObjects(vtkRenderer*, vtkActor*) (vtkOpenGLPolyDataMapper.cxx:2592)
    ==19601==    by 0x6E40ABF: vtkOpenGLPolyDataMapper::RenderPieceStart(vtkRenderer*, vtkActor*) (vtkOpenGLPolyDataMapper.cxx:2394)
    ==19601==    by 0x6E41471: vtkOpenGLPolyDataMapper::RenderPiece(vtkRenderer*, vtkActor*) (vtkOpenGLPolyDataMapper.cxx:2569)
    ==19601==    by 0x7502936: vtkPolyDataMapper::Render(vtkRenderer*, vtkActor*) (vtkPolyDataMapper.cxx:68)
    ==19601==    by 0x6DC6BE3: vtkOpenGLActor::Render(vtkRenderer*, vtkMapper*) (vtkOpenGLActor.cxx:100)
    ==19601==    by 0x73FAC3E: vtkActor::RenderTranslucentPolygonalGeometry(vtkViewport*) (vtkActor.cxx:260)
    ==19601==    by 0x75207CA: vtkRenderer::UpdateTranslucentPolygonalGeometry() (vtkRenderer.cxx:680)
    ==19601==    by 0x6E7712D: vtkOpenGLRenderer::DeviceRenderTranslucentPolygonalGeometry() (vtkOpenGLRenderer.cxx:343)
    ==19601==    by 0x6E7658B: vtkOpenGLRenderer::UpdateGeometry() (vtkOpenGLRenderer.cxx:243)
    ==19601==    by 0x6E75A42: vtkOpenGLRenderer::DeviceRender() (vtkOpenGLRenderer.cxx:170)
    ==19601==    by 0x751F276: vtkRenderer::Render() (vtkRenderer.cxx:351)
    ==19601==    by 0x751CA7D: vtkRendererCollection::Render() (vtkRendererCollection.cxx:51)
    ==19601==    by 0x753B9FE: vtkRenderWindow::DoStereoRender() (vtkRenderWindow.cxx:789)
    ==19601==    by 0x753B8D5: vtkRenderWindow::DoFDRender() (vtkRenderWindow.cxx:758)
    ==19601==    by 0x753B265: vtkRenderWindow::DoAARender() (vtkRenderWindow.cxx:637)
    ==19601==    by 0x753A736: vtkRenderWindow::Render() (vtkRenderWindow.cxx:450)
    ==19601==    by 0x6DB8E3A: vtkGenericOpenGLRenderWindow::Render() (vtkGenericOpenGLRenderWindow.cxx:241)
    ==19601==    by 0x1B70A3: FcRenderer::render() (in /home/toiski/git/project/build/bin/gui)
    ==19601==    by 0x5DC1711: render (qquickframebufferobject.cpp:234)
    ==19601==    by 0x5DC1711: QSGFramebufferObjectNode::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) [clone .part.7] (qquickframebufferobject.moc:74)
    ==19601==    by 0x974D988: QMetaObject::activate(QObject*, int, int, void**) (qobject.cpp:3793)
    ==19601==    by 0x5C934EF: QQuickWindowPrivate::renderSceneGraph(QSize const&) (qquickwindow.cpp:461)
    ==19601==    by 0x5C42F7D: QSGRenderThread::syncAndRender() (qsgthreadedrenderloop.cpp:646)
    ==19601==    by 0x5C4649B: QSGRenderThread::run() (qsgthreadedrenderloop.cpp:730)
    ==19601==    by 0x9554DB2: QThreadPrivate::start(void*) (qthread_unix.cpp:361)
    ==19601==    by 0x9DEF163: start_thread (pthread_create.c:486)
    ==19601==    by 0x9F22DEE: clone (clone.S:95)
    ==19601== 
    ==19601== 124,324,594 bytes in 182 blocks are possibly lost in loss record 23,200 of 23,201
    ==19601==    at 0x483774F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==19601==    by 0x1C296B28: ??? (in /usr/lib/x86_64-linux-gnu/libGLX_nvidia.so.390.116)
    ==19601==    by 0x1D75FD56: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D74AE0C: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D3A01C8: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D3A2765: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x6DCCFAD: vtkOpenGLBufferObject::UploadInternal(void const*, unsigned long, vtkOpenGLBufferObject::ObjectType) (vtkOpenGLBufferObject.cxx:149)
    ==19601==    by 0x6D95513: bool vtkOpenGLBufferObject::Upload<std::vector<unsigned int, std::allocator<unsigned int> > >(std::vector<unsigned int, std::allocator<unsigned int> > const&, vtkOpenGLBufferObject::ObjectType) (vtkOpenGLBufferObject.h:127)
    ==19601==    by 0x6E18DD4: vtkOpenGLIndexBufferObject::CreateTriangleIndexBuffer(vtkCellArray*, vtkPoints*) (vtkOpenGLIndexBufferObject.cxx:193)
    ==19601==    by 0x6E44F40: vtkOpenGLPolyDataMapper::BuildIBO(vtkRenderer*, vtkActor*, vtkPolyData*) (vtkOpenGLPolyDataMapper.cxx:3316)
    ==19601==    by 0x6E44191: vtkOpenGLPolyDataMapper::BuildBufferObjects(vtkRenderer*, vtkActor*) (vtkOpenGLPolyDataMapper.cxx:3218)
    ==19601==    by 0x6E415A9: vtkOpenGLPolyDataMapper::UpdateBufferObjects(vtkRenderer*, vtkActor*) (vtkOpenGLPolyDataMapper.cxx:2592)
    ==19601==    by 0x6E40ABF: vtkOpenGLPolyDataMapper::RenderPieceStart(vtkRenderer*, vtkActor*) (vtkOpenGLPolyDataMapper.cxx:2394)
    ==19601==    by 0x6E41471: vtkOpenGLPolyDataMapper::RenderPiece(vtkRenderer*, vtkActor*) (vtkOpenGLPolyDataMapper.cxx:2569)
    ==19601==    by 0x7502936: vtkPolyDataMapper::Render(vtkRenderer*, vtkActor*) (vtkPolyDataMapper.cxx:68)
    ==19601==    by 0x6DC6BE3: vtkOpenGLActor::Render(vtkRenderer*, vtkMapper*) (vtkOpenGLActor.cxx:100)
    ==19601==    by 0x73FAC3E: vtkActor::RenderTranslucentPolygonalGeometry(vtkViewport*) (vtkActor.cxx:260)
    ==19601==    by 0x75207CA: vtkRenderer::UpdateTranslucentPolygonalGeometry() (vtkRenderer.cxx:680)
    ==19601==    by 0x6E7712D: vtkOpenGLRenderer::DeviceRenderTranslucentPolygonalGeometry() (vtkOpenGLRenderer.cxx:343)
    ==19601==    by 0x6E7658B: vtkOpenGLRenderer::UpdateGeometry() (vtkOpenGLRenderer.cxx:243)
    ==19601==    by 0x6E75A42: vtkOpenGLRenderer::DeviceRender() (vtkOpenGLRenderer.cxx:170)
    ==19601==    by 0x751F276: vtkRenderer::Render() (vtkRenderer.cxx:351)
    ==19601==    by 0x751CA7D: vtkRendererCollection::Render() (vtkRendererCollection.cxx:51)
    ==19601==    by 0x753B9FE: vtkRenderWindow::DoStereoRender() (vtkRenderWindow.cxx:789)
    ==19601==    by 0x753B8D5: vtkRenderWindow::DoFDRender() (vtkRenderWindow.cxx:758)
    ==19601==    by 0x753B265: vtkRenderWindow::DoAARender() (vtkRenderWindow.cxx:637)
    ==19601==    by 0x753A736: vtkRenderWindow::Render() (vtkRenderWindow.cxx:450)
    ==19601==    by 0x6DB8E3A: vtkGenericOpenGLRenderWindow::Render() (vtkGenericOpenGLRenderWindow.cxx:241)
    ==19601==    by 0x1B70A3: FcRenderer::render() (in /home/toiski/git/project/build/bin/gui)
    ==19601==    by 0x5DC1711: render (qquickframebufferobject.cpp:234)
    ==19601==    by 0x5DC1711: QSGFramebufferObjectNode::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) [clone .part.7] (qquickframebufferobject.moc:74)
    ==19601==    by 0x974D988: QMetaObject::activate(QObject*, int, int, void**) (qobject.cpp:3793)
    ==19601==    by 0x5C934EF: QQuickWindowPrivate::renderSceneGraph(QSize const&) (qquickwindow.cpp:461)
    ==19601==    by 0x5C42F7D: QSGRenderThread::syncAndRender() (qsgthreadedrenderloop.cpp:646)
    ==19601==    by 0x5C4649B: QSGRenderThread::run() (qsgthreadedrenderloop.cpp:730)
    ==19601==    by 0x9554DB2: QThreadPrivate::start(void*) (qthread_unix.cpp:361)
    ==19601==    by 0x9DEF163: start_thread (pthread_create.c:486)
    ==19601==    by 0x9F22DEE: clone (clone.S:95)
    ==19601== 
    ==19601== 545,798,049 bytes in 183 blocks are possibly lost in loss record 23,201 of 23,201
    ==19601==    at 0x483774F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==19601==    by 0x1C296B28: ??? (in /usr/lib/x86_64-linux-gnu/libGLX_nvidia.so.390.116)
    ==19601==    by 0x1D75FD56: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D74AE0C: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D82DA13: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D82F38A: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D4930F8: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D498E6F: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D49CC07: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x1D4BA946: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.390.116)
    ==19601==    by 0x6EF2077: vtkTextureObject::Create2DFromRaw(unsigned int, unsigned int, int, int, void*) (vtkTextureObject.cxx:1555)
    ==19601==    by 0x6E96F52: vtkOpenGLTexture::Load(vtkRenderer*) (vtkOpenGLTexture.cxx:306)
    ==19601==    by 0x755F4B9: vtkTexture::Render(vtkRenderer*) (vtkTexture.cxx:350)
    ==19601==    by 0x6E95C33: vtkOpenGLTexture::Render(vtkRenderer*) (vtkOpenGLTexture.cxx:124)
    ==19601==    by 0x73FAB2E: vtkActor::RenderTranslucentPolygonalGeometry(vtkViewport*) (vtkActor.cxx:245)
    ==19601==    by 0x75207CA: vtkRenderer::UpdateTranslucentPolygonalGeometry() (vtkRenderer.cxx:680)
    ==19601==    by 0x6E7712D: vtkOpenGLRenderer::DeviceRenderTranslucentPolygonalGeometry() (vtkOpenGLRenderer.cxx:343)
    ==19601==    by 0x6E7658B: vtkOpenGLRenderer::UpdateGeometry() (vtkOpenGLRenderer.cxx:243)
    ==19601==    by 0x6E75A42: vtkOpenGLRenderer::DeviceRender() (vtkOpenGLRenderer.cxx:170)
    ==19601==    by 0x751F276: vtkRenderer::Render() (vtkRenderer.cxx:351)
    ==19601==    by 0x751CA7D: vtkRendererCollection::Render() (vtkRendererCollection.cxx:51)
    ==19601==    by 0x753B9FE: vtkRenderWindow::DoStereoRender() (vtkRenderWindow.cxx:789)
    ==19601==    by 0x753B8D5: vtkRenderWindow::DoFDRender() (vtkRenderWindow.cxx:758)
    ==19601==    by 0x753B265: vtkRenderWindow::DoAARender() (vtkRenderWindow.cxx:637)
    ==19601==    by 0x753A736: vtkRenderWindow::Render() (vtkRenderWindow.cxx:450)
    ==19601==    by 0x6DB8E3A: vtkGenericOpenGLRenderWindow::Render() (vtkGenericOpenGLRenderWindow.cxx:241)
    ==19601==    by 0x1B70A3: FcRenderer::render() (in /home/toiski/git/project/build/bin/gui)
    ==19601==    by 0x5DC1711: render (qquickframebufferobject.cpp:234)
    ==19601==    by 0x5DC1711: QSGFramebufferObjectNode::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) [clone .part.7] (qquickframebufferobject.moc:74)
    ==19601==    by 0x974D988: QMetaObject::activate(QObject*, int, int, void**) (qobject.cpp:3793)
    ==19601==    by 0x5C934EF: QQuickWindowPrivate::renderSceneGraph(QSize const&) (qquickwindow.cpp:461)
    ==19601==    by 0x5C42F7D: QSGRenderThread::syncAndRender() (qsgthreadedrenderloop.cpp:646)
    ==19601==    by 0x5C4649B: QSGRenderThread::run() (qsgthreadedrenderloop.cpp:730)
    ==19601==    by 0x9554DB2: QThreadPrivate::start(void*) (qthread_unix.cpp:361)
    ==19601==    by 0x9DEF163: start_thread (pthread_create.c:486)
    ==19601==    by 0x9F22DEE: clone (clone.S:95)
    ==19601== 
    ==19601== LEAK SUMMARY:
    ==19601==    definitely lost: 1,141 bytes in 31 blocks
    ==19601==    indirectly lost: 96 bytes in 3 blocks
    ==19601==      possibly lost: 793,037,582 bytes in 2,319 blocks
    ==19601==    still reachable: 29,901,260 bytes in 88,689 blocks
    ==19601==                       of which reachable via heuristic:
    ==19601==                         length64           : 3,376 bytes in 61 blocks
    ==19601==                         newarray           : 152,416 bytes in 168 blocks
    ==19601==                         multipleinheritance: 1,176 bytes in 8 blocks
    ==19601==         suppressed: 0 bytes in 0 blocks

I have checked that the refcounts for the vtkActors go to zero, so they are not kept around forever. I could try instrumenting the VTK code with some debugging if you can think of something to check.