Skip to content

Commit b63b50b

Browse files
authored
Merge pull request #3 from PyLops/fix-mem-leak
Fixes memory leak, closes #2
2 parents ad6aadf + 3523a07 commit b63b50b

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

cpp/fdct2d_wrapper.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,23 @@ vector<vector<py::array_t<cpx>>> fdct2d_forward_wrap(int nbscales, int nbangles_
7474
c[i].resize(cmat[i].size());
7575
for (size_t j = 0; j < cmat[i].size(); j++)
7676
{
77+
// Create capsule linked to `cmat[i][j]._data` to track its lifetime
78+
// https://stackoverflow.com/questions/44659924/returning-numpy-arrays-via-pybind11
79+
py::capsule free_when_done(
80+
cmat[i][j].data(),
81+
[](void *cpx_ptr)
82+
{
83+
cpx *cpx_arr = reinterpret_cast<cpx *>(cpx_ptr);
84+
delete[] cpx_arr;
85+
});
86+
7787
py::array c_arr(
7888
{cmat[i][j]._n, cmat[i][j]._m}, // Shape
7989
{sizeof(cpx) * cmat[i][j]._m, // Strides (in bytes) of the underlying data array
8090
sizeof(cpx)},
81-
cmat[i][j].data()); // Data pointer
91+
cmat[i][j].data(), // Data pointer
92+
free_when_done);
93+
8294
c[i][j] = c_arr;
8395
cmat[i][j]._m = cmat[i][j]._n = 0;
8496
cmat[i][j]._data = NULL;
@@ -128,11 +140,20 @@ py::array_t<cpx> fdct2d_inverse_wrap(int m, int n, int nbscales, int nbangles_co
128140
cmat[i][j]._data = NULL;
129141
}
130142

143+
py::capsule free_when_done(
144+
xmat.data(),
145+
[](void *cpx_ptr)
146+
{
147+
cpx *cpx_arr = reinterpret_cast<cpx *>(cpx_ptr);
148+
delete[] cpx_arr;
149+
});
150+
131151
// Create output array
132152
py::array x({m, n},
133153
{sizeof(cpx),
134154
sizeof(cpx) * m},
135-
xmat.data());
155+
xmat.data(),
156+
free_when_done);
136157

137158
// Clear output structure without deallocating
138159
xmat._m = xmat._n = 0;
@@ -144,7 +165,10 @@ py::array_t<cpx> fdct2d_inverse_wrap(int m, int n, int nbscales, int nbangles_co
144165
PYBIND11_MODULE(fdct2d_wrapper, m)
145166
{
146167
m.doc() = "FDCT2D pybind11 wrapper";
147-
m.def("fdct2d_param_wrap", &fdct2d_param_wrap, "Parameters for 2D FDCT");
148-
m.def("fdct2d_forward_wrap", &fdct2d_forward_wrap, "2D Forward FDCT");
149-
m.def("fdct2d_inverse_wrap", &fdct2d_inverse_wrap, "2D Inverse FDCT");
168+
m.def("fdct2d_param_wrap", &fdct2d_param_wrap, "Parameters for 2D FDCT",
169+
py::return_value_policy::take_ownership);
170+
m.def("fdct2d_forward_wrap", &fdct2d_forward_wrap, "2D Forward FDCT",
171+
py::return_value_policy::take_ownership);
172+
m.def("fdct2d_inverse_wrap", &fdct2d_inverse_wrap, "2D Inverse FDCT",
173+
py::return_value_policy::take_ownership);
150174
}

cpp/fdct3d_wrapper.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,24 @@ vector<vector<py::array_t<cpx>>> fdct3d_forward_wrap(int nbscales, int nbangles_
7171
c[i].resize(ctns[i].size());
7272
for (size_t j = 0; j < ctns[i].size(); j++)
7373
{
74+
// Create capsule linked to `ctns[i][j]._data` to track its lifetime
75+
// https://stackoverflow.com/questions/44659924/returning-numpy-arrays-via-pybind11
76+
py::capsule free_when_done(
77+
ctns[i][j].data(),
78+
[](void *cpx_ptr)
79+
{
80+
cpx *cpx_arr = reinterpret_cast<cpx *>(cpx_ptr);
81+
delete[] cpx_arr;
82+
});
83+
7484
py::array c_arr(
7585
{ctns[i][j]._p, ctns[i][j]._n, ctns[i][j]._m}, // Shape
7686
{sizeof(cpx) * ctns[i][j]._m * ctns[i][j]._n, // Strides (in bytes) of the underlying data array
7787
sizeof(cpx) * ctns[i][j]._m,
7888
sizeof(cpx)},
79-
ctns[i][j].data()); // Data pointer
89+
ctns[i][j].data(), // Data pointer
90+
free_when_done);
91+
8092
c[i][j] = c_arr;
8193
ctns[i][j]._m = ctns[i][j]._n = ctns[i][j]._p = 0;
8294
ctns[i][j]._data = NULL;
@@ -127,12 +139,21 @@ py::array_t<cpx> fdct3d_inverse_wrap(int m, int n, int p, int nbscales, int nban
127139
ctns[i][j]._data = NULL;
128140
}
129141

142+
py::capsule free_when_done(
143+
xtns.data(),
144+
[](void *cpx_ptr)
145+
{
146+
cpx *cpx_arr = reinterpret_cast<cpx *>(cpx_ptr);
147+
delete[] cpx_arr;
148+
});
149+
130150
// Create output array
131151
py::array x({m, n, p},
132152
{sizeof(cpx),
133153
sizeof(cpx) * m,
134154
sizeof(cpx) * m * n},
135-
xtns.data());
155+
xtns.data(),
156+
free_when_done);
136157

137158
// Clear output structure without deallocating
138159
xtns._m = xtns._n = xtns._p = 0;
@@ -144,7 +165,10 @@ py::array_t<cpx> fdct3d_inverse_wrap(int m, int n, int p, int nbscales, int nban
144165
PYBIND11_MODULE(fdct3d_wrapper, m)
145166
{
146167
m.doc() = "FDCT3D pybind11 wrapper";
147-
m.def("fdct3d_param_wrap", &fdct3d_param_wrap, "Parameters for 3D FDCT");
148-
m.def("fdct3d_forward_wrap", &fdct3d_forward_wrap, "3D Forward FDCT");
149-
m.def("fdct3d_inverse_wrap", &fdct3d_inverse_wrap, "3D Inverse FDCT");
168+
m.def("fdct3d_param_wrap", &fdct3d_param_wrap, "Parameters for 3D FDCT",
169+
py::return_value_policy::take_ownership);
170+
m.def("fdct3d_forward_wrap", &fdct3d_forward_wrap, "3D Forward FDCT",
171+
py::return_value_policy::take_ownership);
172+
m.def("fdct3d_inverse_wrap", &fdct3d_inverse_wrap, "3D Inverse FDCT",
173+
py::return_value_policy::take_ownership);
150174
}

0 commit comments

Comments
 (0)