marcomusy / vedo

A python module for scientific analysis of 3D data based on VTK and Numpy
https://vedo.embl.es
MIT License
1.98k stars 257 forks source link

Memory Leak in Image(img), Axes function ? #1130

Closed OhmPuchiss closed 2 weeks ago

OhmPuchiss commented 1 month ago

I spot that when I try to create these elements in the loop it keeps taking more memory even I have delete the object in the end of the function already while I create new circle in every loops and has not seen any leakage of memeory. Can you fix that for me ?

marcomusy commented 1 month ago

I cannot reproduce the problem with the following script

from vedo import *
imgs = []
for i in progressbar(100):
    img = Image(dataurl+'images/watercolors3.jpg')
    # imgs.append(img)

no memory leak detected on my ubuntu system:

vedo version      : 2024.5.1+dev17  (https://vedo.embl.es)       
vtk version       : 9.3.0
numpy version     : 1.26.4
python version    : 3.12.2 | packaged by conda-forge | (main, Feb 16 2024, 20:50:58) [GCC 12.3.0]
python interpreter: /home/musy/soft/miniconda/bin/python
installation point: /home/musy/Projects/vedo
system            : Linux 5.4.0-181-generic posix x86_64
OhmPuchiss commented 4 weeks ago

image image

OhmPuchiss commented 4 weeks ago
from vedo import *
from memory_profiler import profile 
import numpy as np

# Code 1: Problem with Memory Leak
dx = 0.0007
dy = 0.0007

shape = [
            dict(bottomleft=(0,0), topright=(1,1), bg='w'), 
            dict(bottomleft=(0+dx,0+dy), topright=(0.6-dx,1-dy), bg='k'), 
            dict(bottomleft=(0.6+dx,0+dy), topright=(1-dx,0.25-dy), bg='k'),
            dict(bottomleft=(0.6+dx,0.25+dy), topright=(0.8-dx,0.5-dy), bg='k'),
            dict(bottomleft=(0.6+dx,0.5+dy), topright=(0.8-dx,0.75-dy), bg='k'),
            dict(bottomleft=(0.6+dx,0.75+dy), topright=(0.8-dx,1-dy), bg='k'),
            dict(bottomleft=(0.8+dx,0.25+dy), topright=(1-dx,1-dy), bg='k'),
            dict(bottomleft=(0+dx,0+dy), topright=(0.3-dx,0.25-dy), bg='k'), 
            dict(bottomleft=(0.3+dx,0+dy), topright=(0.6-dx,0.25-dy), bg='k')
        ]

plt = Plotter(shape=shape, sharecam=False, size=(1050, 980))

@profile
def func():
    plt.at(7).remove("Image")
    img = np.zeros([512,512])
    img[0:256, 0:256] =   0
    img[0:256,  256:] =  64
    img[256:,  0:256] = 128
    img[256:,   256:] = 255
    img = img.transpose(1,0)
    img1 = Image(img)
    img1.name = "Image"
    plt.at(7).show(img1, zoom="tightest", interactive=False)

    del img1
    del img

while True:
    func()

Code 2: Running fine

plt = Plotter()

@profile
def func():
    plt.remove("Image")
    img = np.zeros([512,512])
    img[0:256, 0:256] =   0
    img[0:256,  256:] =  64
    img[256:,  0:256] = 128
    img[256:,   256:] = 255
    img = img.transpose(1,0)
    img1 = Image(img)
    img1.name = "Image"
    plt.show(img1, zoom="tightest", interactive=False)

    del img1
    del img

while True:
    func()
OhmPuchiss commented 4 weeks ago

image Seem like the problem is in .show function

OhmPuchiss commented 4 weeks ago

plt.at(7).show() creates problem while plt.show() works fine.

marcomusy commented 4 weeks ago

Hi, do not use show(...) inside a loop or callback as it is primarily meant to set up the scene. Use instead render() e.g.:

from vedo import *
from memory_profiler import profile 

# @profile
def func():
    arr = np.zeros([512, 512])
    arr[0:256, 0:256] = np.random.randint(0, 255)
    arr[0:256,  256:] = 64
    arr[256:,  0:256] = np.random.randint(0, 255)
    arr[256:,   256:] = 255
    arr = arr.transpose(1,0)
    img = Image(arr)
    img.name = "Image"
    plt.at(7).remove("Image").add(img)
    plt.reset_camera(tight=0.01).render()

dx = 0.001
dy = 0.001
shape = [
    dict(bottomleft=(0,0),            topright=(1,1), bg='p9'), 
    dict(bottomleft=(0+dx,0+dy),      topright=(0.6-dx,1-dy), bg='k1'), 
    dict(bottomleft=(0.6+dx,0+dy),    topright=(1-dx,0.25-dy), bg='k2'),
    dict(bottomleft=(0.6+dx,0.25+dy), topright=(0.8-dx,0.5-dy), bg='k3'),
    dict(bottomleft=(0.6+dx,0.5+dy),  topright=(0.8-dx,0.75-dy), bg='k4'),
    dict(bottomleft=(0.6+dx,0.75+dy), topright=(0.8-dx,1-dy), bg='k5'),
    dict(bottomleft=(0.8+dx,0.25+dy), topright=(1-dx,1-dy), bg='k6'),
    dict(bottomleft=(0+dx,0+dy),      topright=(0.3-dx,0.25-dy), bg='k7'), 
    dict(bottomleft=(0.3+dx,0+dy),    topright=(0.6-dx,0.25-dy), bg='k8')
]
plt = Plotter(shape=shape, sharecam=False, size=(1050, 980))
plt.parallel_projection()

for i in progressbar(10000):
    func()

Screenshot from 2024-06-03 11-10-09

PS note that the python del doesn't really mean "delete immediately" something, it rather flags the object for the garbage collector to be deleted later (if I remember correctly) by removing it from the function scope.