libigl / libigl-python-bindings

libigl python bindings
https://libigl.github.io/libigl-python-bindings/
GNU General Public License v3.0
315 stars 61 forks source link

adjacency_list will cause memory leak. #147

Open kentechx opened 1 year ago

kentechx commented 1 year ago

igl.adjacency_list will produce memory leak. You can test with the following script. The garbage collector(gc) dosen't help.

import trimesh
import igl
m = trimesh.creation.icosphere()
f = np.array(m.faces)
for _ in range(10000000):
    igl.adjacency_list(f)
alecjacobson commented 1 year ago

This is disturbing!

It seems like this is coming from the binding itself. This similar code in C++ does not cause a memory leak:

#include <igl/adjacency_list.h>
int main()
{
  std::vector<std::vector<int> > A;
  Eigen::MatrixXi F(20,3);
  F <<
    0,11,5,
    0,5,1,
    0,1,7,
    0,7,10,
    0,10,11,
    1,5,9,
    5,11,4,
    11,10,2,
    10,7,6,
    7,1,8,
    3,9,4,
    3,4,2,
    3,2,6,
    3,6,8,
    3,8,9,
    4,9,5,
    2,4,11,
    6,2,10,
    8,6,7,
    9,8,1;
  for(int i = 0;i<100000000;i++)
  {
    igl::adjacency_list(F,A);
  }
}

Not sure the best way to go about debugging this. The good news is that it doesn't seem to be happening to all other bindings

f = np.array(m.faces)
v = np.array(m.vertices)
for _ in range(10000000):
    a = igl.cotmatrix(v,f)

doesn't appear to leak.

Maybe it has to do with numpyeigen/pybind11's treatment of the list-of-lists output from adjacency_list?

dperyel commented 1 year ago

Indeed, memory management for big objects in python is something to be improved. It appears even after removing references, GC releases allocated memory. But memory allocators might not release part of the memory to OS till the process is killed. So with your iterations, more and more memory is allocated, which leads to a collapse. Try to google some addons on better memory usage for Python processes. Or run the computation in a separate process to be sure it is killed after each iteration.