Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added malloc_trim() calls to Python allocator so RSS will decrease when memory is freed #13865

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions upb/python/protobuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
#include "python/repeated.h"
#include "python/unknown_fields.h"

static upb_Arena* PyUpb_NewArena(void);

static void PyUpb_ModuleDealloc(void* module) {
PyUpb_ModuleState* s = PyModule_GetState(module);
PyUpb_WeakMap_Free(s->obj_cache);
Expand Down Expand Up @@ -125,7 +127,7 @@ struct PyUpb_WeakMap {
};

PyUpb_WeakMap* PyUpb_WeakMap_New(void) {
upb_Arena* arena = upb_Arena_New();
upb_Arena* arena = PyUpb_NewArena();
PyUpb_WeakMap* map = upb_Arena_Malloc(arena, sizeof(*map));
map->arena = arena;
upb_inttable_init(&map->table, map->arena);
Expand Down Expand Up @@ -224,10 +226,54 @@ typedef struct {
upb_Arena* arena;
} PyUpb_Arena;

// begin:google_only
// static upb_alloc* global_alloc = &upb_alloc_global;
// end:google_only

// begin:github_only
#ifdef __GLIBC__
#include <malloc.h> // malloc_trim()
#endif

// A special allocator that calls malloc_trim() periodically to release
// memory to the OS. Without this call, we appear to leak memory, at least
// as measured in RSS.
//
// We opt not to use this instead of PyMalloc (which would also solve the
// problem) because the latter requires the GIL to be held. This would make
// our messages unsafe to share with other languages that could free at
// unpredictable
// times.
static void* upb_trim_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize,
size_t size) {
(void)alloc;
(void)oldsize;
if (size == 0) {
free(ptr);
#ifdef __GLIBC__
static int count = 0;
if (++count == 10000) {
malloc_trim(0);
count = 0;
}
#endif
return NULL;
} else {
return realloc(ptr, size);
}
}
static upb_alloc trim_alloc = {&upb_trim_allocfunc};
static const upb_alloc* global_alloc = &trim_alloc;
// end:github_only

static upb_Arena* PyUpb_NewArena(void) {
return upb_Arena_Init(NULL, 0, global_alloc);
}

PyObject* PyUpb_Arena_New(void) {
PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
PyUpb_Arena* arena = (void*)PyType_GenericAlloc(state->arena_type, 0);
arena->arena = upb_Arena_New();
arena->arena = PyUpb_NewArena();
return &arena->ob_base;
}

Expand Down