Skip to content

Having troubble debugging a memory leak from CPython extension #131997

@juliannguyen4

Description

@juliannguyen4

Bug report

Bug description:

Hi all,

There is a memory leak in my CPython extension and I am having trouble figuring out where it is coming from. The details:

  1. The CPython extension is a Python library called the "Python client" that wraps around a shared library written in C, and the wrapper code converts calls to and from that library. Extension: http://github.com/aerospike/aerospike-client-python/
  2. I have a script to reproduce the memory leak. It basically calls an API from the Python client in a loop over 1000 iterations.
  3. This is the API call, which is written entirely in C: https://aerospike-python-client.readthedocs.io/en/latest/client.html#aerospike.Client.batch_write
  4. It takes in an instance of a class defined in native Python code, makes changes to that instance, and then returns the instance: https://aerospike-python-client.readthedocs.io/en/latest/aerospike_helpers.batch.html#aerospike_helpers.batch.records.BatchRecords
  5. I used valgrind's massif tool to print the memory usage of the script (and extension) over time: https://gist.github.com/juliannguyen4/17daa452cb48fe601f3abdf17ead09be. If I run the script with the default Python memory allocator, massif does not detect any heap memory growth. But if I make the script run with PYTHONMALLOC=malloc instead, massif shows that linear growth.

Snippet of the largest allocated memory, during peak memory usage:

89.87% (17,875,409B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->42.51% (8,456,280B) 0x25AA5D: UnknownInlinedFun (dictobject.c:600)
| ->42.51% (8,456,280B) 0x25AA5D: insert_to_emptydict.lto_priv.0 (dictobject.c:1163)
|   ->42.06% (8,367,072B) 0x267749: UnknownInlinedFun (dictobject.c:1620)
|   | ->42.06% (8,367,072B) 0x267749: PyDict_SetItemString (dictobject.c:3614)
|   |   ->25.24% (5,020,008B) 0x53575DE: do_bins_to_pyobject_each (conversions.c:2254)
|   |   | ->25.24% (5,020,008B) 0x535761C: bins_to_pyobject_each (conversions.c:2272)
|   |   |   ->25.24% (5,020,008B) 0x53C489E: as_record_foreach (as_record.c:463)
|   |   |     ->25.24% (5,020,008B) 0x53566E1: bins_to_pyobject (conversions.c:2291)
|   |   |       ->25.24% (5,020,008B) 0x5356960: do_record_to_pyobject (conversions.c:2042)
|   |   |         ->25.24% (5,020,008B) 0x5356A7F: record_to_pyobject (conversions.c:2118)
|   |   |           ->25.24% (5,020,008B) 0x533AF2D: AerospikeClient_BatchWriteInvoke (batch_write.c:491)
|   |   |             ->25.24% (5,020,008B) 0x533B4CD: AerospikeClient_BatchWrite (batch_write.c:574)
|   |   |               ->25.24% (5,020,008B) 0x2940C6: method_vectorcall_VARARGS_KEYWORDS.lto_priv.0 (descrobject.c:344)
  1. I experimented with the extension code by making batch_write() return a Python None instead, and the heap memory usage still grows (albeit at a slightly lesser rate). Massif no longer shows that the memory leaks come from my CPython extension code (snippet of massif report): https://gist.github.com/juliannguyen4/21bc79dddc67250f9f91bc584fdfd0eb

In both cases, the memory leak seems to come from insert_to_emptydict.lto_priv. I reviewed my extension code and could not find why a leak would occur: https://github.com/aerospike/aerospike-client-python/blob/16.0.2/src/main/conversions.c#L2254

Can anybody point me in the right direction? Thanks

CPython versions tested on:

3.10

Operating systems tested on:

Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions