Hi everyone,
I am having a problem with freeing up memory in legacy fenics. As discussed here, with newer versions of petsc4py one should call the destroy method of the objects in order to free up memory ( garbage collection different between petsc4py 3.17.4 and 3.18.3 (#1309) · Issues · PETSc / petsc · GitLab ). However, when I assemble a matrix or vector into the fenics classes, access the underlying petsc4py object with .mat() or .vec() (optionally do some calculations, solve a linear system), and then try to free up the memory by calling A.mat().destroy(), the memory does not get freed and the object is still in memory.
I have the following MWE which shows the problem:
from fenics import *
from petsc4py import PETSc
mesh = UnitSquareMesh(8, 8)
comm = mesh.mpi_comm()
V = FunctionSpace(mesh, "CG", 1)
u = TrialFunction(V)
v = TestFunction(V)
a = dot(grad(u), grad(v)) * dx + u * v * dx
L = Constant(1.0) * v * dx
### Matrices
## First variant
A_fenics = assemble(a)
A_petsc = as_backend_type(A_fenics).mat()
as_backend_type(A_fenics).mat().destroy()
PETSc.garbage_cleanup(comm)
print(A_petsc.getSizes()) # expected: Segfault
## Second variant
A_fenics = PETScMatrix(comm)
A_petsc = A_fenics.mat()
assemble(a, tensor=A_fenics)
A_fenics.mat().destroy()
PETSc.garbage_cleanup(comm)
print(A_petsc.getSizes()) # expected: Segfault
### Vectors
## First variant
b_fenics = assemble(L)
b_petsc = as_backend_type(b_fenics).vec()
as_backend_type(b_fenics).vec().destroy()
PETSc.garbage_cleanup(comm)
print(b_petsc.getSize()) # expected: Segfault
## Second variant
b_fenics = PETScVector(comm)
b_petsc = b_fenics.vec()
assemble(L, tensor=b_fenics)
b_fenics.vec().destroy()
PETSc.garbage_cleanup(comm)
print(b_petsc.getSize()) # expected: Segfault
The memory only gets freed if I call A_petsc.destroy() or b_petsc.destroy(). This is against my understanding of the code, as .mat() or .vec() should return a pointer to the petsc4py object. And if I modify, e.g., the values of the objects, then I see that these changes are reflected in both A_petsc and A_fenics, or in b_petsc and b_fenics, respectively.
Does anyone have a clue to what is going on here and how the memory can be freed correctly?
For context: Of course I don’t want to generate a segfault in my program, but for this test it is an easy way to check whether the memory is still allocated or actually free.
Thanks a lot in advance,
Sebastian