vtkRenderWindow memory leak

Can you, please, share the C++ code of your test?

Here it is, as an MRE. Note that the problem persists even if, as here, the vtkRenderWindow is rendering a blank scene. The preprocessor directives are to quickly verify the issue exists whether one vtkRenderWindow is instantiated for the entire loop and passed in, or within the looped function.

#include <sstream>
#include <vtkPNGWriter.h>
#include <vtkRenderWindow.h>
#include <vtkSmartPointer.h>
#include <vtkWindowToImageFilter.h>

// only turn one of these on at a time
//#define ONE_RENDERER // instantiate vtkRenderWindow outside the loop and pass into fcn
#define MANY_RENDERERS // instantiate vtkRenderWindow inside fcn

void testVTKDataViz(
#ifdef ONE_RENDERER
    vtkSmartPointer<vtkRenderWindow> renWin,
#endif
    std::string OPpath) {
        
#ifdef MANY_RENDERERS
        vtkNew<vtkRenderWindow> renWin;
        renWin->OffScreenRenderingOn();
#endif
        renWin->Render();
        
        vtkNew<vtkWindowToImageFilter> imgf;
        imgf->SetInput(renWin);
        imgf->SetInputBufferTypeToRGB();
        imgf->Update();
        
        vtkNew<vtkPNGWriter> wr;
        wr->SetFileName(OPpath.c_str());
        wr->SetInputConnection(imgf->GetOutputPort());
        wr->Write();
        
#ifdef MANY_RENDERERS
        renWin->Finalize();
#endif
}

int main() {

#ifdef ONE_RENDERER
        auto renWin = vtkSmartPointer<vtkRenderWindow>::New();
        renWin->OffScreenRenderingOn();
#endif
        std::string test_dir = "./imgDump";
        
        for (size_t ii=0; ii<1500; ii++) {
                std::stringstream ssPath;
                ssPath << test_dir << "/sphere_" << ii << ".png";
                std::cout << ssPath.str() << std::endl;
#ifdef MANY_RENDERERS
                testVTKDataViz(ssPath.str());
#endif
#ifdef ONE_RENDERER
                testVTKDataViz(renWin, ssPath.str());
                renWin->Finalize();
#endif
        }
        
        return EXIT_SUCCESS;
}

Does the crash occur with ONE_RENDERER or MANY_RENDERERS?

All those #defines are obfuscating the code.

It occurs in either scenario, that’s why I included them.

Ok. Can you, please, post the simpler (enabled by ONE_RENDERER) one?

Thank you

Sure:

#include <sstream>
#include <vtkPNGWriter.h>
#include <vtkRenderWindow.h>
#include <vtkSmartPointer.h>
#include <vtkWindowToImageFilter.h>


void testVTKDataViz(ER
    vtkSmartPointer<vtkRenderWindow> renWin,
    std::string OPpath) {
        
        renWin->Render();
        
        vtkNew<vtkWindowToImageFilter> imgf;
        imgf->SetInput(renWin);
        imgf->SetInputBufferTypeToRGB();
        imgf->Update();
        
        vtkNew<vtkPNGWriter> wr;
        wr->SetFileName(OPpath.c_str());
        wr->SetInputConnection(imgf->GetOutputPort());
        wr->Write();
        
}

int main() {

        auto renWin = vtkSmartPointer<vtkRenderWindow>::New();
        renWin->OffScreenRenderingOn();
        std::string test_dir = "./imgDump";
        
        for (size_t ii=0; ii<1500; ii++) {
                std::stringstream ssPath;
                ssPath << test_dir << "/sphere_" << ii << ".png";
                std::cout << ssPath.str() << std::endl;R
                testVTKDataViz(renWin, ssPath.str());
                renWin->Finalize();
        }
        
        return EXIT_SUCCESS;
}
1 Like

If you look into the code of vtkWindowToImageFilter’s SetInput() method:

void vtkWindowToImageFilter::SetInput(vtkWindow* input)
{
  if (input != this->Input)
  {
    if (this->Input)
    {
      this->Input->UnRegister(this);
    }
    this->Input = input;
    if (this->Input)
    {
      this->Input->Register(this);
    }
    this->Modified();
  }
}

Notice the vtkObjectBase::Register() method which, in the end, prevents the instance from being deallocated once its smart pointer goes out of the scope, hence the “memory leak”. You need to call imgf->SetInput(nullptr) to un-register the instance with the renWin object before leaving the scope of testVTKDataViz(). The way your test is coded, getting that VTK warning is expected.

Thanks for the suggestion. I tried it and am still having the same issue. Sequential calls to imgf->GetInput() before and after imgf->SetInput(nullptr) result in the following:

0x7faaebc04080
0x0

This seemingly confirms the vtkRenderWindow has been released by the vtkWindowToImageFilter. However, the memory problem remains. For good measure I tried also to SetInputConnection(nullptr) on the vtkPNGWriter, but no effect.

Make sure you pass the null pointers while still inside the testVTKDataViz() function:

void testVTKDataViz(ER
    vtkSmartPointer<vtkRenderWindow> renWin,
    std::string OPpath) {
        
        renWin->Render();
        
        vtkNew<vtkWindowToImageFilter> imgf;
        imgf->SetInput(renWin);
        imgf->SetInputBufferTypeToRGB();
        imgf->Update();
        
        vtkNew<vtkPNGWriter> wr;
        wr->SetFileName(OPpath.c_str());
        wr->SetInputConnection(imgf->GetOutputPort());
        wr->Write();

        imgf->SetInput(nullptr);
        wr->SetInputConnection(nullptr);
        
}

Yes, they’re inside the testVTKDataViz() function.

Since you already have a simple code that reproduces the issue, please, report a bug here: https://gitlab.kitware.com/vtk/vtk/-/issues

I’m attempting to report it but keep getting flagged as spam. I’ll wait an hour or so then try again.

Ok, done.

I suppose it was this issue: https://gitlab.kitware.com/vtk/vtk/-/issues/19268 ?

The content of your issue seems unrelated to the discussion here.

@Paulo_Carvalho I did not follow the whole discussion but this looks like misuse to me, not an issue, am I missing something ?

Hello, Mathieu,

Yes, it can be a misuse, but I believe the API should quit with at least a failed assert or pop up one of those VTK messages so the user knows s/he’s doing it wrong. An abend is not a good response to misuse in my opinion.

regards,

PC

Ok, @Zachary_Stamler , could you explain that issue ? because right now the name of the issue: “vtkRenderWindow loop instantiation results in many open windows” does not fit with an abort when incorrectly using the API.

Well I am a researcher and engineer, not a computer scientist, so perhaps I’m fuzzy on the distinction. What happens is simply that windows keep opening and memory keeps allocating to the point where the entire system becomes unresponsive, though the the memory is actually not being utilized fully according to htop, so it could be the bottleneck is somewhere else, maybe in the graphics engine.

I’m unclear on the meaning of your response to the bug report. Doesn’t a window interactor necessitate a user to manually close the window? This would make it impossible, or anyhow impractical, to render a series of images in a loop, no? EDIT FOR CLARIFICATION: what is needed is a way to leave a very long process running, possibly for hours, that is able to generate a series of images, for later review, without any user interaction.

If there is a good thorough primer on this somewhere I’d love a link to it, as none of these usage conventions/requirements are at all clear or obvious trying to work from class documentation or from examples.

Hello,

An interactor is an interpreter of user’s gestures (e.g. dragging → rotate). Although not strictly necessary, the presence of an interactor seems to be a requirement, even if it does nothing.

I don’t see any problems with that. You can perfectly make animations loops in VTK regardless of window interactor. Actually, you can interact with the scene while the animation is running.

You don’t need to get rid of the interactor for it. You can apply transforms (e.g. rotate, translate, etc.) to the model/scene while capturing the screen in a loop.

I recommend perusing the VTK primer so you get acquainted with how VTK works: VTK Textbook | VTK . If you can’t afford the time to read, please, take a look at the examples for a more hands-on experience: https://examples.vtk.org/site/ .

regards,

PC

1 Like

Hi again Paulo,

Thank you so much for the link, I’ll have a look.

Unfortunately what I’m after is not so much animations where the perspective on an existing surface is dynamically changed, but rather a series of images to evaluate the performance of an algorithm that modifies the data in discrete steps. In other words, the data is modified with a certain parameter, the scene rendered and output as a file, then the data is modified again with a different parameter, etc etc. So it is necessary, as far as I can tell, to generate a new scene with every step.

I do find the requirement for an interactor odd. I guess VTK is more oriented towards generating animations or interactive scenes, but for someone who just needs to use the geometric algorithms and generate images, this is not such a friendly idiom, even though the library is quite capable of doing everything I’m asking of it.

Thanks again for your attention and advice on this.

-Z