From eed1a8762f3a2a800e48ae604d9087cfe2df7bdc Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Sun, 16 Oct 2022 17:23:01 -0700 Subject: [PATCH] `amrex::Finalize()` w/ `gc.collect()` When calling `amrex.finalize()`, first call the Python garbage collector. This is purely a bandage to make usage like this easy: ```py import amrex amrex.initialize([]) mfab = amrex.MultiFab( ... ) del mfab amrex.finalize() ``` Respect the Python standard guarantees without furhter headache, by running an explicit call to the garbage collector. Previously, this was only working with CPython, but alternative implementations like PyPy might delay the true free due to time based memory collection approaches. --- src/Base/AMReX.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Base/AMReX.cpp b/src/Base/AMReX.cpp index dfccda07..c1107682 100644 --- a/src/Base/AMReX.cpp +++ b/src/Base/AMReX.cpp @@ -103,7 +103,25 @@ void init_AMReX(py::module& m) }, py::return_value_policy::reference, "Initialize AMReX library"); + constexpr auto run_gc = []() { + // explicitly run the garbage collector, so deleted objects + // get freed. + // This is a convenience helper/bandage for making work with Python + // garbage collectors in various implementations more easy. + // https://github.com/AMReX-Codes/pyamrex/issues/81 + auto m_gc = py::module::import("gc"); + auto collect = m_gc.attr("collect"); + collect(); + }; + + m.def("finalize", + [run_gc]() { + run_gc(); + amrex::Finalize(); + }); m.def("finalize", - py::overload_cast<>(&Finalize)); - m.def("finalize", py::overload_cast(&Finalize)); + [run_gc](AMReX* pamrex) { + run_gc(); + amrex::Finalize(pamrex); + }); }