fix(solvers): dispose the solver model before its env on close - #899
fix(solvers): dispose the solver model before its env on close#899FabianHofmann wants to merge 4 commits into
Conversation
Solver.close() closed the env ExitStack before dropping solver_model, so the native model was collected against freed memory — a Fatal Python error or Windows access violation from an unrelated GC pass. COPT also closed its env in a finally while returning the model built in it; the env now lives on the solver's ExitStack.
Merging this PR will regress 2 benchmarks
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ | Memory | test_to_lp[storage-n=250] |
30.3 MB | 36.3 MB | -16.6% |
| ❌ | Memory | test_to_lp[nodal_balance-severity=50] |
2.9 MB | 3.4 MB | -14.5% |
| ⚡ | Memory | test_to_lp[milp-n=50] |
2.6 MB | 2 MB | +29.32% |
| ⚡ | Memory | test_to_lp[masked-n=100] |
2.7 MB | 2.1 MB | +29.19% |
| ⚡ | Memory | test_to_lp[knapsack-n=10000] |
2.7 MB | 2.2 MB | +17.93% |
| ⚡ | Memory | test_to_lp[cumsum-severity=50] |
62.5 MB | 53.6 MB | +16.51% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing fix/solver-close-ordering (f3a4405) with master (f06738e)
Footnotes
-
175 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
d97a8d1 to
f3a4405
Compare
Build cost — v1 vs legacyv1 build peak & time relative to legacy, on this commit — not a comparison against master (that is CodSpeed).
Full table (time + peak, mean)📊 Interactive plots + CSV: download the semantics-report-v1-vs-legacy artifact from this run. Report-only · not a gate · refreshed on every push · obsolete once legacy is dropped. |
The current CI on master is flaky with COPT, let's test if it has to do with the potential issue raised and fixed here
Note
The following content was generated by AI.
Changes proposed in this Pull Request
Solver.close()closed the environment before dropping the model that lives in it:Solvers that register their model on the environment's
ExitStack— Gurobi (since #826), Xpress, Mosek — get the right LIFO ordering and were unaffected. HiGHS, SCIP, COPT and MindOpt only dereference the model, so its native destructor ran against a freed environment. Becauseclose()is also called from__del__, the crash lands in whatever code happened to trigger the collection, which makes it look unrelated and intermittent.This is what CI has been hitting on
master:Windows fatal exception: access violation, faulting framesolvers.pyclose()atself.solver_model = None, reached from__del__during a garbage collection pass inside unrelatedxarrayalignment code.Fatal Python error: AbortedinsideCOPT._run_fileatenv_.createModel()— a later COPT call aborting on state a previous freed model corrupted.Two changes:
Solver.close()dropssolver_modelfirst, then closes the environment stack. For solvers whose model sits on the stack this is a no-op (the stack still holds the reference and disposes it first); for the others the model is now released while its environment is still alive.COPT._run_fileno longer closes its environment in afinallywhile returning the model built in it. The environment is registered on the solver'sExitStack, so it is released bySolver.close()andmodel.solver_modelstays usable aftermodel.solve("copt")— matching Gurobi's behaviour.Verification
Both crashes are macOS/Windows-only and were not reproducible on Linux, so this fix is validated by CI rather than locally. Locally (Linux, Python 3.13) the full suite passes: 2980 passed, 33 skipped, with
test/remoteand Xpress excluded — Xpress is deselected because of an unrelated local install problem (NameError: name 'xpress' is not defined), andtest/remoteneeds OETC credentials.mypyreports no new errors, andruff check/ruff formatare clean.test_copt_env_persists_after_solvepins the COPT invariant. It is skipped locally (no valid COPT licence on this machine) and runs on the CI hosts where COPT is licensed.Crash traceback (Windows, master and PR #717)
Crash traceback (macOS, master run 32129308681)
Checklist
AGENTS.md).doc.doc/release_notes.rstof the upcoming release is included.