Skip to content

Commit be0708f

Browse files
committed
Closes python#19831: Stop tracemalloc later at Python shutdown to be able to use
tracemalloc in objects destructor Replace atexit handler with an harcoded C function _PyTraceMalloc_Fini().
1 parent 54532c9 commit be0708f

2 files changed

Lines changed: 15 additions & 67 deletions

File tree

‎Modules/_tracemalloc.c‎

Lines changed: 10 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
/* Forward declaration */
1111
static void tracemalloc_stop(void);
12-
static int tracemalloc_atexit_register(void);
1312
static void* raw_malloc(size_t size);
1413
static void raw_free(void *ptr);
1514

@@ -36,17 +35,14 @@ static struct {
3635
TRACEMALLOC_FINALIZED
3736
} initialized;
3837

39-
/* atexit handler registered? */
40-
int atexit_registered;
41-
4238
/* Is tracemalloc tracing memory allocations?
4339
Variable protected by the GIL */
4440
int tracing;
4541

4642
/* limit of the number of frames in a traceback, 1 by default.
4743
Variable protected by the GIL. */
4844
int max_nframe;
49-
} tracemalloc_config = {TRACEMALLOC_NOT_INITIALIZED, 0, 0, 1};
45+
} tracemalloc_config = {TRACEMALLOC_NOT_INITIALIZED, 0, 1};
5046

5147
#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
5248
/* This lock is needed because tracemalloc_free() is called without
@@ -802,9 +798,6 @@ tracemalloc_start(int max_nframe)
802798
return 0;
803799
}
804800

805-
if (tracemalloc_atexit_register() < 0)
806-
return -1;
807-
808801
assert(1 <= max_nframe && max_nframe <= MAX_NFRAME);
809802
tracemalloc_config.max_nframe = max_nframe;
810803

@@ -1140,65 +1133,6 @@ py_tracemalloc_get_object_traceback(PyObject *self, PyObject *obj)
11401133
return traceback_to_pyobject(trace.traceback, NULL);
11411134
}
11421135

1143-
static PyObject*
1144-
tracemalloc_atexit(PyObject *self)
1145-
{
1146-
#ifdef WITH_THREAD
1147-
assert(PyGILState_Check());
1148-
#endif
1149-
tracemalloc_deinit();
1150-
Py_RETURN_NONE;
1151-
}
1152-
1153-
static PyMethodDef atexit_method = {
1154-
"_atexit", (PyCFunction)tracemalloc_atexit, METH_NOARGS, NULL};
1155-
1156-
static int
1157-
tracemalloc_atexit_register(void)
1158-
{
1159-
PyObject *method = NULL, *atexit = NULL, *func = NULL;
1160-
PyObject *result;
1161-
int ret = -1;
1162-
1163-
if (tracemalloc_config.atexit_registered)
1164-
return 0;
1165-
tracemalloc_config.atexit_registered = 1;
1166-
1167-
/* private functions */
1168-
method = PyCFunction_New(&atexit_method, NULL);
1169-
if (method == NULL)
1170-
goto done;
1171-
1172-
atexit = PyImport_ImportModule("atexit");
1173-
if (atexit == NULL) {
1174-
if (!PyErr_Warn(PyExc_ImportWarning,
1175-
"atexit module is missing: "
1176-
"cannot automatically disable tracemalloc at exit"))
1177-
{
1178-
PyErr_Clear();
1179-
return 0;
1180-
}
1181-
goto done;
1182-
}
1183-
1184-
func = PyObject_GetAttrString(atexit, "register");
1185-
if (func == NULL)
1186-
goto done;
1187-
1188-
result = PyObject_CallFunction(func, "O", method);
1189-
if (result == NULL)
1190-
goto done;
1191-
Py_DECREF(result);
1192-
1193-
ret = 0;
1194-
1195-
done:
1196-
Py_XDECREF(method);
1197-
Py_XDECREF(func);
1198-
Py_XDECREF(atexit);
1199-
return ret;
1200-
}
1201-
12021136
PyDoc_STRVAR(tracemalloc_start_doc,
12031137
"start(nframe: int=1)\n"
12041138
"\n"
@@ -1439,3 +1373,12 @@ _PyTraceMalloc_Init(void)
14391373
return tracemalloc_start(nframe);
14401374
}
14411375

1376+
void
1377+
_PyTraceMalloc_Fini(void)
1378+
{
1379+
#ifdef WITH_THREAD
1380+
assert(PyGILState_Check());
1381+
#endif
1382+
tracemalloc_deinit();
1383+
}
1384+

‎Python/pythonrun.c‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ extern int _PyFaulthandler_Init(void);
106106
extern void _PyFaulthandler_Fini(void);
107107
extern void _PyHash_Fini(void);
108108
extern int _PyTraceMalloc_Init(void);
109+
extern int _PyTraceMalloc_Fini(void);
109110

110111
#ifdef WITH_THREAD
111112
extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *);
@@ -642,6 +643,10 @@ Py_Finalize(void)
642643
PyGC_Collect();
643644
#endif
644645

646+
/* Disable tracemalloc after all Python objects have been destroyed,
647+
so it is possible to use tracemalloc in objects destructor. */
648+
_PyTraceMalloc_Fini();
649+
645650
/* Destroy the database used by _PyImport_{Fixup,Find}Extension */
646651
_PyImport_Fini();
647652

0 commit comments

Comments
 (0)