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.4

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.4
File Size Uploaded
cymem-2.0.4.tar.gz 56.5 kB Details

Built distributions (wheels)

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

Total release size: 469.7 kB

Release files / cymem-2.0.4.tar.gz

Download URL cymem-2.0.4.tar.gz
Size 56.5 kB
Tags Source
SHA-256 checksum
How to use checksums
2baabeb408e4aaa0f51d7f6d8c53dd05f56decf34fb3f1f3180abe8755815890
BLAKE2b-256 checksum
How to use checksums
ef258cb4d3dfce05cd261adadfec0cbc4d90a7ddf6abac888b2d354042986b64
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-cp39-cp39-win_amd64.whl
Size 36.0 kB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
58f49a51bd8b76b260f38f8274ec2e4613c328423e0b543a503834de32dfa3c4
BLAKE2b-256 checksum
How to use checksums
48c56f9518cfcf3c826250879beaa1acc861d914bb0109f6397260b055220625
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-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
45b01ee36ce15aab6df041b4128de38016e3934274b934c44fec43de5100b64c
BLAKE2b-256 checksum
How to use checksums
09f83e590d4d1793b7c72ce6055f2448177fc6ca07669c669bba1720f59eef14
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-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
0f169ee07f30c2674ca811693cb13857e236dd7f92b4bc47b0f2bb201e27cc93
BLAKE2b-256 checksum
How to use checksums
37b0bc3d12c36eefdfc13a0a9d47c9bd9f4cebc08cf6db658b4c14f498523619
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-cp38-cp38-win_amd64.whl
Size 36.3 kB
Tags CPython 3.8 Windows x86-64
SHA-256 checksum
How to use checksums
ae283889f6f0036fb34d12358fe052d4ea9f5724f05177317f33f302f304b47c
BLAKE2b-256 checksum
How to use checksums
35162c61c46614c3f0474690969fbed6d28b3912bdde4842c21618b8eda76686
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-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
a61a4702dcc50ebd31fb86a90d1aba5526245af592d756c39c63d58d53360afc
BLAKE2b-256 checksum
How to use checksums
bae0ccc3693dff0887225084f521f2adeb25a9805c2d4086f8beffbf6613b8b1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-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
7bb5791fde8dffa02005f158f5c98d64962adaf8501dac7a9b8156b8767c9a34
BLAKE2b-256 checksum
How to use checksums
457a209a557087d90f1f8c008629461a9983780b061be31e35e2154b96c23e23
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-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
2d40dfa4b4edf64541192966c67c2706e5058a9c6ce0bdc356e4d6ef1935c9ae
BLAKE2b-256 checksum
How to use checksums
08a06210b235a731799ed80ba991b4cdfd9d2fc3a876f8fbad20e97b1169b85a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-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
f8f280f0aef46d32655b1b24ff049bea83b63365604b6c2decb112b44ed851fe
BLAKE2b-256 checksum
How to use checksums
e493d63c12f492cd9e463e67554fd187adce4efc94451aca1f825caf2f310140
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-cp37-cp37m-macosx_10_9_x86_64.whl
Size 31.7 kB
Tags CPython 3.7 CPython 3.7 pymalloc macOS 10.9+ x86-64
SHA-256 checksum
How to use checksums
a61684d01a1413049e9874e073c9577d406d866eabe0d167c5ee15bbeae090a6
BLAKE2b-256 checksum
How to use checksums
4b6c9112bc14037d4bb8f7bdfc1c2dcef070e7310a81746c23e6086e83c54373
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-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
02c3994ee57003dd57d9a34417beb9597e51176e9378a757344347b72510ce8d
BLAKE2b-256 checksum
How to use checksums
494de65903173537b7cfa05f96d367558454e20b6f06db4f6ab36266f39b1347
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-cp36-cp36m-manylinux2014_x86_64.whl
Size 35.3 kB
Tags CPython 3.6 CPython 3.6 pymalloc Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
65e5759179b311b8350b82b29744324366e270f96095b16a8e249c73c3f9273f
BLAKE2b-256 checksum
How to use checksums
178f7e15cd364c0a66c5b3c5300a11a1a72348de59a5c39ad9cefd88c462217b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.7.9

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

Download URL cymem-2.0.4-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
60b5d969f305a7598d86f34c93c37eb52b3388681e70b98081864f0f185da768
BLAKE2b-256 checksum
How to use checksums
efb32f9c5b93f22975b23009df0174bbd5c0f4a9732f33186e5eab5ae38e5107
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.51.0 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