Skip to main content

cymem: A Cython Memory Helper

cymem provides two small memory-management helpers for Cython. They make it easy to tie memory to a Python object's life-cycle, so that the memory is freed when the object is garbage collected.

Azure Pipelines pypi Version conda Version Python wheels

Overview

The most useful is cymem.Pool, which acts as a thin wrapper around the calloc function:

from cymem.cymem cimport Pool
cdef Pool mem = Pool()
data1 = <int*>mem.alloc(10, sizeof(int))
data2 = <float*>mem.alloc(12, sizeof(float))

The Pool object saves the memory addresses internally, and frees them when the object is garbage collected. Typically you'll attach the Pool to some cdef'd class. This is particularly handy for deeply nested structs, which have complicated initialization functions. Just pass the Pool object into the initializer, and you don't have to worry about freeing your struct at all — all of the calls to Pool.alloc will be automatically freed when the Pool expires.

Installation

Installation is via pip, and requires Cython. Before installing, make sure that your pip, setuptools and wheel are up to date.

pip install -U pip setuptools wheel
pip install cymem

Example Use Case: An array of structs

Let's say we want a sequence of sparse matrices. We need fast access, and a Python list isn't performing well enough. So, we want a C-array or C++ vector, which means we need the sparse matrix to be a C-level struct — it can't be a Python class. We can write this easily enough in Cython:

"""Example without Cymem

To use an array of structs, we must carefully walk the data structure when
we deallocate it.
"""

from libc.stdlib cimport calloc, free

cdef struct SparseRow:
    size_t length
    size_t* indices
    double* values

cdef struct SparseMatrix:
    size_t length
    SparseRow* rows

cdef class MatrixArray:
    cdef size_t length
    cdef SparseMatrix** matrices

    def __cinit__(self, list py_matrices):
        self.length = 0
        self.matrices = NULL

    def __init__(self, list py_matrices):
        self.length = len(py_matrices)
        self.matrices = <SparseMatrix**>calloc(len(py_matrices), sizeof(SparseMatrix*))

        for i, py_matrix in enumerate(py_matrices):
            self.matrices[i] = sparse_matrix_init(py_matrix)

    def __dealloc__(self):
        for i in range(self.length):
            sparse_matrix_free(self.matrices[i])
        free(self.matrices)


cdef SparseMatrix* sparse_matrix_init(list py_matrix) except NULL:
    sm = <SparseMatrix*>calloc(1, sizeof(SparseMatrix))
    sm.length = len(py_matrix)
    sm.rows = <SparseRow*>calloc(sm.length, sizeof(SparseRow))
    cdef size_t i, j
    cdef dict py_row
    cdef size_t idx
    cdef double value
    for i, py_row in enumerate(py_matrix):
        sm.rows[i].length = len(py_row)
        sm.rows[i].indices = <size_t*>calloc(sm.rows[i].length, sizeof(size_t))
        sm.rows[i].values = <double*>calloc(sm.rows[i].length, sizeof(double))
        for j, (idx, value) in enumerate(py_row.items()):
            sm.rows[i].indices[j] = idx
            sm.rows[i].values[j] = value
    return sm


cdef void* sparse_matrix_free(SparseMatrix* sm) except *:
    cdef size_t i
    for i in range(sm.length):
        free(sm.rows[i].indices)
        free(sm.rows[i].values)
    free(sm.rows)
    free(sm)

We wrap the data structure in a Python ref-counted class at as low a level as we can, given our performance constraints. This allows us to allocate and free the memory in the __cinit__ and __dealloc__ Cython special methods.

However, it's very easy to make mistakes when writing the __dealloc__ and sparse_matrix_free functions, leading to memory leaks. cymem prevents you from writing these deallocators at all. Instead, you write as follows:

"""Example with Cymem.

Memory allocation is hidden behind the Pool class, which remembers the
addresses it gives out.  When the Pool object is garbage collected, all of
its addresses are freed.

We don't need to write MatrixArray.__dealloc__ or sparse_matrix_free,
eliminating a common class of bugs.
"""
from cymem.cymem cimport Pool

cdef struct SparseRow:
    size_t length
    size_t* indices
    double* values

cdef struct SparseMatrix:
    size_t length
    SparseRow* rows


cdef class MatrixArray:
    cdef size_t length
    cdef SparseMatrix** matrices
    cdef Pool mem

    def __cinit__(self, list py_matrices):
        self.mem = None
        self.length = 0
        self.matrices = NULL

    def __init__(self, list py_matrices):
        self.mem = Pool()
        self.length = len(py_matrices)
        self.matrices = <SparseMatrix**>self.mem.alloc(self.length, sizeof(SparseMatrix*))
        for i, py_matrix in enumerate(py_matrices):
            self.matrices[i] = sparse_matrix_init(self.mem, py_matrix)

cdef SparseMatrix* sparse_matrix_init_cymem(Pool mem, list py_matrix) except NULL:
    sm = <SparseMatrix*>mem.alloc(1, sizeof(SparseMatrix))
    sm.length = len(py_matrix)
    sm.rows = <SparseRow*>mem.alloc(sm.length, sizeof(SparseRow))
    cdef size_t i, j
    cdef dict py_row
    cdef size_t idx
    cdef double value
    for i, py_row in enumerate(py_matrix):
        sm.rows[i].length = len(py_row)
        sm.rows[i].indices = <size_t*>mem.alloc(sm.rows[i].length, sizeof(size_t))
        sm.rows[i].values = <double*>mem.alloc(sm.rows[i].length, sizeof(double))
        for j, (idx, value) in enumerate(py_row.items()):
            sm.rows[i].indices[j] = idx
            sm.rows[i].values[j] = value
    return sm

All that the Pool class does is remember the addresses it gives out. When the MatrixArray object is garbage-collected, the Pool object will also be garbage collected, which triggers a call to Pool.__dealloc__. The Pool then frees all of its addresses. This saves you from walking back over your nested data structures to free them, eliminating a common class of errors.

Custom Allocators

Sometimes external C libraries use private functions to allocate and free objects, but we'd still like the laziness of the Pool.

from cymem.cymem cimport Pool, WrapMalloc, WrapFree
cdef Pool mem = Pool(WrapMalloc(priv_malloc), WrapFree(priv_free))

Metadata

Release files for cymem 2.0.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cymem 2.0.5
File Size Uploaded
cymem-2.0.5.tar.gz 9.2 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for cymem 2.0.5
File
cymem-2.0.5-cp39-cp39-win_amd64.whl CPython 3.9 CPython 3.9 Windows x86-64 Details
cymem-2.0.5-cp39-cp39-manylinux2014_x86_64.whl CPython 3.9 CPython 3.9 Linux glibc 2.17+ x86-64 Details
cymem-2.0.5-cp39-cp39-macosx_10_9_x86_64.whl CPython 3.9 CPython 3.9 macOS 10.9+ x86-64 Details
cymem-2.0.5-cp38-cp38-win_amd64.whl CPython 3.8 CPython 3.8 Windows x86-64 Details
cymem-2.0.5-cp38-cp38-manylinux2014_x86_64.whl CPython 3.8 CPython 3.8 Linux glibc 2.17+ x86-64 Details
cymem-2.0.5-cp38-cp38-macosx_10_9_x86_64.whl CPython 3.8 CPython 3.8 macOS 10.9+ x86-64 Details
cymem-2.0.5-cp37-cp37m-win_amd64.whl CPython 3.7 CPython 3.7 pymalloc Windows x86-64 Details
cymem-2.0.5-cp37-cp37m-manylinux2014_x86_64.whl CPython 3.7 CPython 3.7 pymalloc Linux glibc 2.17+ x86-64 Details
cymem-2.0.5-cp37-cp37m-macosx_10_9_x86_64.whl CPython 3.7 CPython 3.7 pymalloc macOS 10.9+ x86-64 Details
cymem-2.0.5-cp36-cp36m-win_amd64.whl CPython 3.6 CPython 3.6 pymalloc Windows x86-64 Details
cymem-2.0.5-cp36-cp36m-manylinux2014_x86_64.whl CPython 3.6 CPython 3.6 pymalloc Linux glibc 2.17+ x86-64 Details
cymem-2.0.5-cp36-cp36m-macosx_10_9_x86_64.whl CPython 3.6 CPython 3.6 pymalloc macOS 10.9+ x86-64 Details

Total release size: 422.5 kB

Release files / cymem-2.0.5.tar.gz

Download URL cymem-2.0.5.tar.gz
Size 9.2 kB
Tags Source
SHA-256 checksum
How to use checksums
190e15d9cf2c3bde60ae37bddbae6568a36044dc4a326d84081a5fa08818eee0
BLAKE2b-256 checksum
How to use checksums
3efb5899a59ee8d0f02202c1f02fe47671e0c93d1812b1deb2491505718473da
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp39-cp39-win_amd64.whl

Download URL cymem-2.0.5-cp39-cp39-win_amd64.whl
Size 36.0 kB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
d19f68b90411e02ab33b1654118337f96f41c13a3cd00c4f44f7abed2bc712e7
BLAKE2b-256 checksum
How to use checksums
262005f075a74328056dadce4d9d866ccc6845a955a5fd56f20f923aba37d370
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp39-cp39-manylinux2014_x86_64.whl

Download URL cymem-2.0.5-cp39-cp39-manylinux2014_x86_64.whl
Size 34.8 kB
Tags CPython 3.9 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
ce1e81c1d031f56b67bac2136e73b4512cbc794706cd570178972d54ba6115d8
BLAKE2b-256 checksum
How to use checksums
4523c93fc6f6baa276ab862186ced15ca1da9e7503ea532499922ed2208808d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp39-cp39-macosx_10_9_x86_64.whl

Download URL cymem-2.0.5-cp39-cp39-macosx_10_9_x86_64.whl
Size 32.5 kB
Tags CPython 3.9 macOS 10.9+ x86-64
SHA-256 checksum
How to use checksums
d307f7f6230d861a938837cae4b855226b6845a21c010242a15e9ce6853856cd
BLAKE2b-256 checksum
How to use checksums
3b67a1b90e26d3b705fb07ce2510623279427eb80a6cdd87086dc8d28eb8a068
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp38-cp38-win_amd64.whl

Download URL cymem-2.0.5-cp38-cp38-win_amd64.whl
Size 36.3 kB
Tags CPython 3.8 Windows x86-64
SHA-256 checksum
How to use checksums
01d3ea159f7a3f3192b1e800ed8207dac7586794d903a153198b9ea317f144bc
BLAKE2b-256 checksum
How to use checksums
3f2fd18320a639dd3d4a5cc25e76fc023dee31a0b172d069914edf6e38e1fa7b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp38-cp38-manylinux2014_x86_64.whl

Download URL cymem-2.0.5-cp38-cp38-manylinux2014_x86_64.whl
Size 35.8 kB
Tags CPython 3.8 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
734d82d0d03c2ceb929bc1744c04dbe0a105e68a4947c8406056a36f86c41830
BLAKE2b-256 checksum
How to use checksums
365a04fcc4f69d519d4ab7de1ed503f9ca723d54c6e363c1276296efcd11b82c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp38-cp38-macosx_10_9_x86_64.whl

Download URL cymem-2.0.5-cp38-cp38-macosx_10_9_x86_64.whl
Size 31.9 kB
Tags CPython 3.8 macOS 10.9+ x86-64
SHA-256 checksum
How to use checksums
f2167c9959fcd639b95d51fa5efaa7c61eef8d686cb75a25412a914f428ce980
BLAKE2b-256 checksum
How to use checksums
1eed3cead6a7aff2a9ab7abfae37449082a257703b44436dedb65b16bbe74cbd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp37-cp37m-win_amd64.whl

Download URL cymem-2.0.5-cp37-cp37m-win_amd64.whl
Size 35.7 kB
Tags CPython 3.7 CPython 3.7 pymalloc Windows x86-64
SHA-256 checksum
How to use checksums
3d48902d7441645835fefc7832df49feb5362c7300d182475b63a01d25ae44ef
BLAKE2b-256 checksum
How to use checksums
3f7fe4b81e6355e87c08a039cbc64c3044046ba4665a74e9b62246c71976a849
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp37-cp37m-manylinux2014_x86_64.whl

Download URL cymem-2.0.5-cp37-cp37m-manylinux2014_x86_64.whl
Size 35.3 kB
Tags CPython 3.7 CPython 3.7 pymalloc Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
a440d63577fcdc9c528c9cc026b7b4f8648193bac462bc0596c9eac10f9fba62
BLAKE2b-256 checksum
How to use checksums
b63440547e057c1b31080c1d78f6accf9f1ed6ee46e3fc7ebd8599197915ef89
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp37-cp37m-macosx_10_9_x86_64.whl

Download URL cymem-2.0.5-cp37-cp37m-macosx_10_9_x86_64.whl
Size 31.8 kB
Tags CPython 3.7 CPython 3.7 pymalloc macOS 10.9+ x86-64
SHA-256 checksum
How to use checksums
1f0eb9b3d03623dcfc746cf8bff0663b0e347f4aea759965c8932087a0307ee9
BLAKE2b-256 checksum
How to use checksums
f5e4270d7d5b64528480f6f9923325266486ab286c014ce83610d7bc43368218
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp36-cp36m-win_amd64.whl

Download URL cymem-2.0.5-cp36-cp36m-win_amd64.whl
Size 35.8 kB
Tags CPython 3.6 CPython 3.6 pymalloc Windows x86-64
SHA-256 checksum
How to use checksums
4bd023c2477198b39b660c2a6b0242880649765ecee8461688a57fd4afd2bfc0
BLAKE2b-256 checksum
How to use checksums
ff32363ecc81d058387028e59f4c39e3e469a546f1ba597b3f4d1211a2442741
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp36-cp36m-manylinux2014_x86_64.whl

Download URL cymem-2.0.5-cp36-cp36m-manylinux2014_x86_64.whl
Size 35.4 kB
Tags CPython 3.6 CPython 3.6 pymalloc Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
8ea57e6923f40eb51012352161bb5707c14a5a5ce901ff72021e59df06221655
BLAKE2b-256 checksum
How to use checksums
6a52d4c2070b724faa3168339c610e909e990f17b3d5d2e56083338410a1a3ee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9

Release files / cymem-2.0.5-cp36-cp36m-macosx_10_9_x86_64.whl

Download URL cymem-2.0.5-cp36-cp36m-macosx_10_9_x86_64.whl
Size 32.1 kB
Tags CPython 3.6 CPython 3.6 pymalloc macOS 10.9+ x86-64
SHA-256 checksum
How to use checksums
9d72d69f7a62a280199c3aa7bc550685c47d6d0689b2d299e6492253b86d2437
BLAKE2b-256 checksum
How to use checksums
47ea42f07b1d2dff1d6d53b1693ce861aca2acedd1368c06fe5cdf7d6e0ad36c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.9
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page