question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Memory Leak Using Plotter and Screenshot

See original GitHub issue

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
--------------------------------------------------------------------------------

Issue Analytics

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

github_iconTop GitHub Comments

3reactions
leo2rcommented, Sep 9, 2022

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!

1reaction
RichardScottOZcommented, May 10, 2022

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

Read more comments on GitHub >

github_iconTop Results From Across the Web

3 steps to fix app memory leaks - Streamlit Blog
1. Identify the memory leak ... A leak happens when your app acquires memory resources and never releases them. It just consumes more...
Read more >
Memory profiling in Python with tracemalloc - Simple Talk
You can find memory leaks in Python code with tracemalloc. ... The profiler works by letting you take a snapshot of memory during...
Read more >
Mystery Memory Leak: Where Did My Memory Go?!
This blog addresses how to troubleshoot unaccounted memory usage or leak to include identifying and data collection.
Read more >
Taking a memory snapshot - memtools
In garabage collected languages, memory leaks occur when some object or entity unexpectedly contains or points to an object that is otherwise no...
Read more >
c# - Continuous creation of bitmaps leads to memory leak
In my case Bitmap.Dispose() and using Graphics g = Graphics.FromImage(Bitmap) eliminated memory leak. Could you say why in case Graphics g ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found