Skip to content

Question about memory management in PyOSQPSolver::get_solution() #198

@XiDianZuoYun

Description

@XiDianZuoYun

Question about memory management in PyOSQPSolver::get_solution()

Version

  • osqp-python: v1.0.5
  • Python: 3.10
  • OS: Linux

Background

I'm investigating a memory growth issue in my application and Valgrind is reporting what appears to be a memory leak originating from PyOSQPSolver::get_solution(). However, I suspect I might be misunderstanding the intended design.

Code in Question

In src/bindings.cpp.in (lines 167-171):

PyOSQPSolution& PyOSQPSolver::get_solution() {
    PyOSQPSolution* solution = new PyOSQPSolution(*this->_solver->solution, this->m, this->n);
    return *solution;
}

Combined with the binding (line 492):

.def_property_readonly("solution", &PyOSQPSolver::get_solution, py::return_value_policy::reference)

My Understanding (possibly incorrect)

From my reading:

  • Each call to get_solution() allocates a new PyOSQPSolution on the heap
  • py::return_value_policy::reference tells pybind11 not to manage this object's lifetime
  • I don't see where these objects are deleted

However, the Python layer (interface.py lines 426-429) accesses .solution multiple times per solve:

x=self._solver.solution.x,
y=self._solver.solution.y,
prim_inf_cert=self._solver.solution.prim_inf_cert,
dual_inf_cert=self._solver.solution.dual_inf_cert,

Valgrind Output

My application with ~400k solves shows:

==3130== 50,680,976 bytes in 3,167,559 blocks are definitely lost
==3130==    at 0x483CF83: operator new(unsigned long)
==3130==    by 0x14D53CA21: PyOSQPSolver::get_solution() (bindings.cpp:169)

My Question

Am I missing something about how these objects are managed?

I'm hesitant to conclude this is a bug because:

  • This code has been in use for a while
  • There might be a cleanup path I'm not seeing
  • Perhaps the reference policy has different semantics than I understand

Could someone clarify the intended lifetime management for these PyOSQPSolution objects? Is there a design reason for allocating them on the heap with new rather than returning by value?

Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions