Memory leak occurs if I use vtkSmartPointer in sub-thread.

I’m trying to create vtkPolyData from implicit functions.
But this code makes memory leak if I use std::thread.
Does anyone know the workarounds?
I’m using Linux debian11 and vtk 9.0.1 on x86_64 PC.

#include <iostream>
#include <string>
#include <thread>
#include <unistd.h>   // for getpid()
#include <vtkContourFilter.h>
#include <vtkSmartPointer.h>
#include <vtkSampleFunction.h>
#include <vtkSphere.h>
#include <vtkPolyData.h>

long getProcessMemKB()
{
    static const long sz = getpagesize();  // bytes per a page
    std::string statmPath = "/proc/" + std::to_string(getpid()) + "/statm";
    std::ifstream ifs(statmPath.c_str());
    if(ifs.fail()) {
        return -1;
    } else {
        std::string buff;
        ifs >> buff;  // virtual memory (pages)
        ifs >> buff;  // physical memory (pages)
        return static_cast<long>(std::stol(buff)*sz/1024);
    }
}

std::pair<int, vtkSmartPointer<vtkPolyData>> create(int count)
{
    auto sphereSource = vtkSmartPointer<vtkSphere>::New();
    sphereSource->SetRadius(5.0);

    auto sample = vtkSmartPointer<vtkSampleFunction>::New();
    sample->SetImplicitFunction(sphereSource);
    sample->SetModelBounds(-10, 10, -10, 10, -10, 10);
    sample->SetSampleDimensions(100, 100, 100);
    sample->Update();

    auto surface = vtkSmartPointer<vtkContourFilter>::New();
    surface->SetInputConnection(sample->GetOutputPort());
    surface->Update();
    auto polyData = vtkSmartPointer<vtkPolyData>::New();
    polyData->DeepCopy(surface->GetOutput());
    return std::make_pair(count, polyData);
}

int main()
{
    int count = 0;
    while(true) {
        std::pair<int, vtkSmartPointer<vtkPolyData>> retval;

        // Memory leak occurs.
        std::thread t([&](){retval = create(++count);});
        t.join();

        // If executing in main thread, it's OK.
        // retval = create(++count);

        std::cout << "count = " << retval.first << ", Memory(MB) = " << getProcessMemKB()/1000 << std::endl;
        // doing something below in the actual code.
    }
    return 0;
}
1 Like

This problem is sollved.
I recompiled vtk libraries with changing the “VTK_SMP_IMPLEMENTION_TYPE” from OpenMP to sequential.
The memory leak stopped.

FYI @Charles_Gueunet

Can you give further details on how the memory leak was detected ? Did you try the VTK_DEBUG_LEAKS macro or it is only the getProcessMemKB result?

I found it just by the memory usage.
I created a littel more compact code including vtkDebugLeaks.

#include <iostream>
#include <string>
#include <thread>
#include <unistd.h>   // for getpid()
#include <vtkContourFilter.h>
#include <vtkSmartPointer.h>
#include <vtkSampleFunction.h>
#include <vtkSphere.h>
#include <vtkDebugLeaks.h>

long getProcessMem()
{
    static const long sz = getpagesize();  // bytes per a page
    std::string statmPath = "/proc/" + std::to_string(getpid()) + "/statm";
    std::ifstream ifs(statmPath.c_str());
    if(ifs.fail()) return -1;
    std::string buff;
    ifs >> buff; ifs >> buff;  // virtual, then physical memory (pages)
    return static_cast<long>(std::stol(buff)*sz);
}

void create()
{
    auto sphere = vtkSmartPointer<vtkSphere>::New();
    sphere->SetRadius(5.0);
    auto sample = vtkSmartPointer<vtkSampleFunction>::New();
    sample->SetImplicitFunction(sphere);
    auto surface = vtkSmartPointer<vtkContourFilter>::New();
    surface->SetInputConnection(sample->GetOutputPort());
    surface->Update(); // If comment out this line, memory usage dosen't increase.
}

int main()
{
    int count = 0;
    while(++count < 1000) {
        std::thread t1([](){create();}); // sub-thread execution
        std::thread t2([](){create();});
        t2.join();
        t1.join();
        //create();  // In the main thread.  It's OK.
        std::cout << "count = " << count << ", Memory(kB) = " << getProcessMem()/1024  << std::endl;
    }
    return 0;
}

The output (VTK_SMP_IMPLEMENTION_TYPE = OpenMP) is

count = 1, Memory(kB) = 29492
count = 2, Memory(kB) = 34204
...
count = 999, Memory(kB) = 581352
vtkDebugLeaks has detected LEAKS!
Class "vtkObjectFactoryCollection" has 1 instance still around.

If executing create() in the main thread, the output is

count = 1, Memory(kB) = 29688
count = 2, Memory(kB) = 32356
...
count = 999, Memory(kB) = 32356

Finally, I found there is no solution.

In any setting (VTK_SMP_IMPLEMENTION_TYPE = OpenMP, sequential, TBB, or stdthread), the error message Class "vtkObjectFactoryCollection" has 1 instance still around. , which indicates a memory leak, will appear.

“VTK_SMP_IMPLEMENTION_TYPE = sequential” can not perfectly prevent memory leaks, but it can reduce the amount of leakage.