Skip to content

Commit c2c857b

Browse files
authored
bpo-44895: Introduce PYTHONDUMPREFSFILE variable for refcount dumping (GH-27767)
1 parent 96346cb commit c2c857b

File tree

5 files changed

+41
-0
lines changed

5 files changed

+41
-0
lines changed

Doc/using/cmdline.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,3 +975,12 @@ Debug-mode variables
975975
shutting down the interpreter.
976976

977977
Need Python configured with the :option:`--with-trace-refs` build option.
978+
979+
.. envvar:: PYTHONDUMPREFSFILE=FILENAME
980+
981+
If set, Python will dump objects and reference counts still alive
982+
after shutting down the interpreter into a file called *FILENAME*.
983+
984+
Need Python configured with the :option:`--with-trace-refs` build option.
985+
986+
.. versionadded:: 3.11

Include/cpython/initconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ typedef struct PyConfig {
143143
int no_debug_ranges;
144144
int show_ref_count;
145145
int dump_refs;
146+
wchar_t *dump_refs_file;
146147
int malloc_stats;
147148
wchar_t *filesystem_encoding;
148149
wchar_t *filesystem_errors;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
A debug variable :envvar:`PYTHONDUMPREFSFILE` is added for creating a dump file
2+
which is generated by :option:`--with-trace-refs`. Patch by Dong-hee Na.

Python/initconfig.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,7 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2)
898898
COPY_ATTR(no_debug_ranges);
899899
COPY_ATTR(show_ref_count);
900900
COPY_ATTR(dump_refs);
901+
COPY_ATTR(dump_refs_file);
901902
COPY_ATTR(malloc_stats);
902903

903904
COPY_WSTR_ATTR(pycache_prefix);
@@ -1701,6 +1702,14 @@ config_read_env_vars(PyConfig *config)
17011702
config->malloc_stats = 1;
17021703
}
17031704

1705+
if (config->dump_refs_file == NULL) {
1706+
status = CONFIG_GET_ENV_DUP(config, &config->dump_refs_file,
1707+
L"PYTHONDUMPREFSFILE", "PYTHONDUMPREFSFILE");
1708+
if (_PyStatus_EXCEPTION(status)) {
1709+
return status;
1710+
}
1711+
}
1712+
17041713
if (config->pythonpath_env == NULL) {
17051714
status = CONFIG_GET_ENV_DUP(config, &config->pythonpath_env,
17061715
L"PYTHONPATH", "PYTHONPATH");

Python/pylifecycle.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,6 +1737,7 @@ Py_FinalizeEx(void)
17371737
#endif
17381738
#ifdef Py_TRACE_REFS
17391739
int dump_refs = tstate->interp->config.dump_refs;
1740+
wchar_t *dump_refs_file = tstate->interp->config.dump_refs_file;
17401741
#endif
17411742
#ifdef WITH_PYMALLOC
17421743
int malloc_stats = tstate->interp->config.malloc_stats;
@@ -1835,9 +1836,22 @@ Py_FinalizeEx(void)
18351836
* Alas, a lot of stuff may still be alive now that will be cleaned
18361837
* up later.
18371838
*/
1839+
1840+
FILE *dump_refs_fp = NULL;
1841+
if (dump_refs_file != NULL) {
1842+
dump_refs_fp = _Py_wfopen(dump_refs_file, L"w");
1843+
if (dump_refs_fp == NULL) {
1844+
fprintf(stderr, "PYTHONDUMPREFSFILE: cannot create file: %ls\n", dump_refs_file);
1845+
}
1846+
}
1847+
18381848
if (dump_refs) {
18391849
_Py_PrintReferences(stderr);
18401850
}
1851+
1852+
if (dump_refs_fp != NULL) {
1853+
_Py_PrintReferences(dump_refs_fp);
1854+
}
18411855
#endif /* Py_TRACE_REFS */
18421856

18431857
finalize_interp_clear(tstate);
@@ -1848,9 +1862,15 @@ Py_FinalizeEx(void)
18481862
* An address can be used to find the repr of the object, printed
18491863
* above by _Py_PrintReferences.
18501864
*/
1865+
18511866
if (dump_refs) {
18521867
_Py_PrintReferenceAddresses(stderr);
18531868
}
1869+
1870+
if (dump_refs_fp != NULL) {
1871+
_Py_PrintReferenceAddresses(dump_refs_fp);
1872+
fclose(dump_refs_fp);
1873+
}
18541874
#endif /* Py_TRACE_REFS */
18551875
#ifdef WITH_PYMALLOC
18561876
if (malloc_stats) {

0 commit comments

Comments
 (0)