Repository navigation
Py_Finalize() doesn't clear all Python objects at exit #44470
Description
Activity
This C code:
#include <Python.h> int main(int argc, char *argv[]) { Py_Initialize(); Py_Finalize(); Py_Initialize(); Py_Finalize(); Py_Initialize(); Py_Finalize(); Py_Initialize(); Py_Finalize(); Py_Initialize(); Py_Finalize(); Py_Initialize(); Py_Finalize(); Py_Initialize(); Py_Finalize(); }
Produces this output:
[7438 refs]
[7499 refs]
[7550 refs]
[7601 refs]
[7652 refs]
[7703 refs]
[7754 refs]A similar program configured to call the Py_Initialize()/Py_Finalize() 1000 times ends up with:
...
[58295 refs]
[58346 refs]
[58397 refs]This is with a fresh debug build of Python 2.5.0 on Windows XP, using Visual C++ 2003.
- addedinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
on Jan 15, 2007 - addedperformancePerformance or resource usagePerformance or resource usage
on Mar 30, 2009 Does the title of this issue accurately reflect the current status of the Python interpreter?
Yes, some objects are not cleaned in finalization.
This is not a problem in usual cases though, when the interpreter is
started only once.Does the title of this issue accurately reflect the current status of the Python interpreter?
Yes, here is the running result on current 3.3 latest code:
[37182 refs]
[39415 refs]
[41607 refs]
[43799 refs]
[45991 refs]
[48183 refs]
[50375 refs]This seems to be a known bug that Py_Finalize() doesn't free all objects according doc http://docs.python.org/dev/c-api/init.html?highlight=py_finalize#Py_Finalize
Interestingly enough, some of the leaked memory came from the finalize routine itself! Here's one example:
0:004> !heap -p -a 0x000000DB144346F0
address 000000db144346f0 found in
_HEAP @ db0cae0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
000000db14434690 030a 0000 [00] 000000db144346c0 03074 - (busy)
7ffc55628b04 ntdll!RtlpCallInterceptRoutine+0x0000000000000040
7ffc555f9f36 ntdll!RtlAllocateHeap+0x0000000000079836
7ffc2a60c4da ucrtbased!calloc_base+0x000000000000123a
7ffc2a60c27d ucrtbased!calloc_base+0x0000000000000fdd
7ffc2a60f34f ucrtbased!malloc_dbg+0x000000000000002f
7ffc2a60fdde ucrtbased!malloc+0x000000000000001e
5a5e6ef9 python36_d!_PyMem_RawMalloc+0x0000000000000029
5a5e78c7 python36_d!_PyMem_DebugAlloc+0x0000000000000087
5a5e5e6f python36_d!_PyMem_DebugMalloc+0x000000000000001f
5a5e7230 python36_d!PyMem_Malloc+0x0000000000000030
5a582047 python36_d!new_keys_object+0x0000000000000077
5a57f7c5 python36_d!dictresize+0x0000000000000085
5a57a4b2 python36_d!PyDict_Merge+0x0000000000000112
5a57bf33 python36_d!PyDict_Update+0x0000000000000023
5a75fb1d python36_d!PyImport_Cleanup+0x000000000000045d
5a778f9e python36_d!Py_Finalize+0x000000000000005eI tested on the master branch of Python:
---#include <Python.h> void func() { Py_Initialize(); Py_Finalize(); Py_ssize_t cnt = _Py_GetRefTotal(); printf("sys.gettotalrefcount(): %zd\n", cnt); } int main(int argc, char *argv[]) { Py_SetProgramName(L"./_testembed"); for (int i=0; i < 10; i++) { func(); } }
Each iteration leaks around 5,000 Python objects:
---
sys.gettotalrefcount(): 15113
sys.gettotalrefcount(): 19527
sys.gettotalrefcount(): 23941
sys.gettotalrefcount(): 28355
sys.gettotalrefcount(): 32769
sys.gettotalrefcount(): 37183
sys.gettotalrefcount(): 41597
sys.gettotalrefcount(): 46011
sys.gettotalrefcount(): 50425
sys.gettotalrefcount(): 54839
---- changed the title
[-]Interpreter seems to leak references after finalization[/-][+]Py_Finalize() doesn't clear all Python objects at exit[/+]on Oct 23, 2019 - changed the title
[-]Interpreter seems to leak references after finalization[/-][+]Py_Finalize() doesn't clear all Python objects at exit[/+]on Oct 23, 2019 I marked bpo-6741 as a duplicate of this issue.
199 remaining items
Load more actionsThanks to recent enhancements, epecially in bpo-46417, the last memory blocks are now released at Python exit! The initial issue has been fixed!!! This bug was 15 years old! Current main branch:
$ ./python -I -X showrefcount -c pass [-5 refs, 0 blocks]
"0 blocks" means that Python no longer leaks memory at exit. You can use Valgrind to check it ;-)
The negative reference count is being discussed in bpo-46449.
I close this issue since it has an insane history: too many pull requests, changes, etc.
While the work is not 100% done (we need to convert remaining static types to heap types, and convert extensions to multi-phase init), I prefer to address remaining issues in (existing or new) separated issues. See for example the bpo-40077: "Convert static types to heap types: use PyType_FromSpec()".
I would like to thank everybody who helped to fix this issue! It's hard to list all names since this issue is a meta issues made of many sub-issues which also have sub-issues. Authors of PEP-573 and PEP-630 also helped fixing this issue!
- added3.11only security fixesonly security fixesand removed3.10 (EOL)end of lifeend of life
on Jan 27, 2022 - added3.11only security fixesonly security fixesand removed3.10 (EOL)end of lifeend of life
on Jan 27, 2022 I marked bpo-35774 as a duplicate of this issue.
The negative refcount issue has been fixed ;-)
At commit 9a24127, Python now leaks exactly 0 reference count and 0 memory block at exit:
$ ./python -I -X showrefcount -c pass [0 refs, 0 blocks]
New changeset c9c178f by Victor Stinner in branch 'main':
bpo-1635741: test_embed cheks that Python does not leak (GH-31555)
c9c178fNew changeset 4657bf7 by Victor Stinner in branch 'main':
bpo-1635741: Fix winreg reference leaks (GH-31560)
4657bf7I have teste Python 3.11 "3.11.0rc1 (main, Aug 8 2022, 11:30:54) [MSC v.1932 64 bit (AMD64)]" in Win10 64 bits and it leaks around 2Mb each time you call
Py_IsInitialized();
Py_FinalizeEx();This issue is closed, please open a new issue.
I have teste Python 3.11 "3.11.0rc1 (main, Aug 8 2022, 11:30:54) [MSC v.1932 64 bit (AMD64)]" in Win10 64 bits and it leaks around 2Mb each time you call
Ah, it seems like it has been reported as a new issue: #96853
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields: