|
36 | 36 | #include "python/repeated.h" |
37 | 37 | #include "python/unknown_fields.h" |
38 | 38 |
|
| 39 | +static upb_Arena* PyUpb_NewArena(void); |
| 40 | + |
39 | 41 | static void PyUpb_ModuleDealloc(void* module) { |
40 | 42 | PyUpb_ModuleState* s = PyModule_GetState(module); |
41 | 43 | PyUpb_WeakMap_Free(s->obj_cache); |
@@ -122,7 +124,7 @@ struct PyUpb_WeakMap { |
122 | 124 | }; |
123 | 125 |
|
124 | 126 | PyUpb_WeakMap* PyUpb_WeakMap_New(void) { |
125 | | - upb_Arena* arena = upb_Arena_New(); |
| 127 | + upb_Arena* arena = PyUpb_NewArena(); |
126 | 128 | PyUpb_WeakMap* map = upb_Arena_Malloc(arena, sizeof(*map)); |
127 | 129 | map->arena = arena; |
128 | 130 | upb_inttable_init(&map->table, map->arena); |
@@ -221,10 +223,54 @@ typedef struct { |
221 | 223 | upb_Arena* arena; |
222 | 224 | } PyUpb_Arena; |
223 | 225 |
|
| 226 | +// begin:google_only |
| 227 | +// static upb_alloc* global_alloc = &upb_alloc_global; |
| 228 | +// end:google_only |
| 229 | + |
| 230 | +// begin:github_only |
| 231 | +#ifdef __GLIBC__ |
| 232 | +#include <malloc.h> // malloc_trim() |
| 233 | +#endif |
| 234 | + |
| 235 | +// A special allocator that calls malloc_trim() periodically to release |
| 236 | +// memory to the OS. Without this call, we appear to leak memory, at least |
| 237 | +// as measured in RSS. |
| 238 | +// |
| 239 | +// We opt not to use this instead of PyMalloc (which would also solve the |
| 240 | +// problem) because the latter requires the GIL to be held. This would make |
| 241 | +// our messages unsafe to share with other languages that could free at |
| 242 | +// unpredictable |
| 243 | +// times. |
| 244 | +static void* upb_trim_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, |
| 245 | + size_t size) { |
| 246 | + (void)alloc; |
| 247 | + (void)oldsize; |
| 248 | + if (size == 0) { |
| 249 | + free(ptr); |
| 250 | +#ifdef __GLIBC__ |
| 251 | + static int count = 0; |
| 252 | + if (++count == 10000) { |
| 253 | + malloc_trim(0); |
| 254 | + count = 0; |
| 255 | + } |
| 256 | +#endif |
| 257 | + return NULL; |
| 258 | + } else { |
| 259 | + return realloc(ptr, size); |
| 260 | + } |
| 261 | +} |
| 262 | +static upb_alloc trim_alloc = {&upb_trim_allocfunc}; |
| 263 | +static const upb_alloc* global_alloc = &trim_alloc; |
| 264 | +// end:github_only |
| 265 | + |
| 266 | +static upb_Arena* PyUpb_NewArena(void) { |
| 267 | + return upb_Arena_Init(NULL, 0, global_alloc); |
| 268 | +} |
| 269 | + |
224 | 270 | PyObject* PyUpb_Arena_New(void) { |
225 | 271 | PyUpb_ModuleState* state = PyUpb_ModuleState_Get(); |
226 | 272 | PyUpb_Arena* arena = (void*)PyType_GenericAlloc(state->arena_type, 0); |
227 | | - arena->arena = upb_Arena_New(); |
| 273 | + arena->arena = PyUpb_NewArena(); |
228 | 274 | return &arena->ob_base; |
229 | 275 | } |
230 | 276 |
|
|
0 commit comments