pyvista: Memory Leak Using Plotter and Screenshot

Memory Leak Using Plotter and Screenshot

It seems that Plotter.screenshot() produces a memory leak. I am currently running an iterative program implementing the observer pattern, where after each iteration (i.e. when the observer is notified), the observer plots and saves (as a .png) OpenFOAM data.

What I notice in my Activity Monitor is that after each time the observer is called and executed (i.e. PlotVTK.update() is run), my python memory increases by around ~70MB, which becomes a problem when the observer is called around 300 times, when memory consumption has increased to many many GBs.

I have noticed that when I comment out p.screenshot(f'plot_{iteration}', window_size=[1000,1000], return_img = False) , my memory increase after each observer call is much smaller, i.e. 5MB. Although, when I don’t call this observer at all, my memory increase after each observer call in <1MB.

Any help would be appreciated.

My code

import Observer
import pyvista as pv

class PlotVTK(Observer):
    
    def update(self, subject) -> None:
        
        # Get current iteration
        iteration = subject.iteration
        
        # Open openfoam file
        reader = pv.OpenFOAMReader(f'test_{iteration}.foam')

        # Obtain data for latest snapshot
        reader.set_active_time_value(reader.time_values[-1])

        # Read data into mesh
        mesh = reader.read()

        # Extract internal mesh data
        internalMesh = mesh["internalMesh"].slice_orthogonal()

        # Create plotting environment
        p = pv.Plotter(off_screen = True)

        # Plot velocity diagram
        p.add_mesh(internalMesh, scalars = 'U')

        # Set viewing angle
        p.view_xy()
        p.camera_position = ((0, 0, 3), (0, 0, 0), (0, 0, 0))
        
        # Take screenshot of image and save in appropriate directory
        p.screenshot(f'plot_{iteration}', window_size=[1000,1000], return_img = False)

        # Clear plot data (i.e. release memory)
        p.clear()

System Information:


--------------------------------------------------------------------------------
  Date: Mon Feb 21 16:38:57 2022 GMT

                OS : Darwin
            CPU(s) : 8
           Machine : x86_64
      Architecture : 64bit
               RAM : 16.0 GiB
       Environment : IPython
       File system : apfs
        GPU Vendor : Apple
      GPU Renderer : Apple M1
       GPU Version : 4.1 Metal - 76.3

  Python 3.9.7 (default, Sep 16 2021, 08:50:36)  [Clang 10.0.0 ]

           pyvista : 0.33.2
               vtk : 9.1.0
             numpy : 1.21.2
           imageio : 2.16.0
           appdirs : 1.4.4
            scooby : 0.5.11
        matplotlib : 3.5.0
           IPython : 7.29.0
        ipyvtklink : 0.2.2
             scipy : 1.7.3
              tqdm : 4.62.3
--------------------------------------------------------------------------------

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 1
  • Comments: 27 (18 by maintainers)

Most upvoted comments

So I’ve been having the same problem for ages, and actually just managed to fix it now! I was creating a new Plotter instance in my method that was getting called at each step, and instead I took it out and made it a Class variable and just call pl.clear() at the start of the method. So my code now looks like this:

class Env
    pl = pv.Plotter(off_screen=True)

    def get_image(self, cpos=[0, 0, 0], croll=0):
        self.pl.clear()
        self.pl.add_mesh(self.bone_mesh, color="lightblue", opacity=0.3) 
        self.pl.camera.position = cpos
        self.pl.camera.focal_point = (0,0,0)
        self.pl.camera.roll = croll
        img = self.pl.screenshot(None, return_img=True, window_size=(self.WINDOW_SIZE))
        img = img[..., :1]
        return img

It seems like there’s no more memory hogging now and my code that used to slow down and freeze my computer at around 80 steps has run for well over 3000 steps now with no slowing down!

I have also been experiencing this issue on my Macbook M1. So far I’ve tried turning off the call to the renderer.ResetCamera() based off this old discussion as well as call the following after every screenshot() call but am still getting major memory leak.

del pvmesh
del plotter.ren_win
plotter.close()
plotter.deep_clean()
pv.plotting._ALL_PLOTTERS.pop(plotter._id_name)
plotter.renderers = None
delattr(plotter, 'renderers')
plotter._theme = None
del plotter
pv.close_all()

I will try and give that a shot this afternoon, have to go out shortly.

Yes, strange! I was doing a bunch with screenshots the other day and things were getting slow…but I wasn’t monitoring memory.