-
For some reason I see leak warnings at program exit when passing a certain Python objects to a C++ class with Nanobind bindings. For example for Is this expected? Is there something wrong with the C++ code or bindings? The error message is the following:
Here is the extension and the Python code. #include <iostream>
#include <nanobind/nanobind.h>
namespace nb = nanobind;
using namespace nb::literals;
class Test {
public:
Test(nb::object x) : x(x) { }
nb::object x;
};
NB_MODULE(my_ext, m) {
nb::class_<Test>(m, "Test").def(nb::init<nb::object>(), "f"_a);
} import my_ext
# Doesn't leak
# x = 3
# Leaks
def x():
pass
y = my_ext.Test(x) Edit: I have read through the relevant section in the docs.
|
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 9 replies
-
I think this is an expected reference and unrelated to nanobind, i.e.: you would have a leak here with other binding frameworks as well, they just wouldn't warn you about it. Your This is actually a nice and concise way to illustrate a problem that people often aren't aware of, I think I'll integrate it into the FAQ. |
Beta Was this translation helpful? Give feedback.
-
@wjakob here's a complete example which shows the problem using It feels ike #include <nanobind/nanobind.h>
#include <nanobind/stl/function.h>
namespace nb = nanobind;
using namespace nb::literals;
nb::object func_ret(nb::callable f) {
return nb::cpp_function([f](int i) { return i+1; }, nb::arg("number"));
}
class Test {
public:
Test() { };
};
NB_MODULE(my_ext, m) {
m.def("func_ret", &func_ret);
nb::class_<Test>(m, "Test").def(nb::init<>());
} import my_ext
def x():
pass
t = my_ext.Test()
y = my_ext.func_ret(x) |
Beta Was this translation helpful? Give feedback.
I think this is an expected reference and unrelated to nanobind, i.e.: you would have a leak here with other binding frameworks as well, they just wouldn't warn you about it.
Your
x
function implicitly depends onglobals()
, which in turn containsy
, which referencesx
. To inform Python that this is a collectable cycle, you'll have to implementtp_traverse
for yourTest
type.This is actually a nice and concise way to illustrate a problem that people often aren't aware of, I think I'll integrate it into the FAQ.