metal : fix more leaks due to missing autoreleasepools (#27883)

* metal : fix more leaks due to missing autoreleasepools

* metal : rename variable

* metal : fix another missing pool warning

Co-authored-by: YiChen Lv <63285796+forforever73@users.noreply.github.com>

---------

Co-authored-by: YiChen Lv <63285796+forforever73@users.noreply.github.com>
This commit is contained in:
Niklas Wenzel
2026-09-01 13:50:47 +02:00
committed by GitHub
co-authored by YiChen Lv
parent d08c7872d6
commit fe2120bc9d
2 changed files with 43 additions and 19 deletions
+18
View File
@@ -69,6 +69,10 @@ struct ggml_metal {
// extra command buffers for things like getting, setting and copying tensors // extra command buffers for things like getting, setting and copying tensors
NSMutableArray * cmd_bufs_ext; NSMutableArray * cmd_bufs_ext;
// buffers to release after async Metal operations complete
// if Metal released them, it would do so on a Metal-internal thread without an autorelease pool, which could cause leaks
NSMutableArray * buf_refs;
// the last command buffer queued into the Metal queue with operations relevant to the current Metal backend // the last command buffer queued into the Metal queue with operations relevant to the current Metal backend
id<MTLCommandBuffer> cmd_buf_last; id<MTLCommandBuffer> cmd_buf_last;
@@ -179,6 +183,7 @@ ggml_metal_t ggml_metal_init(ggml_metal_device_t dev) {
} }
res->cmd_bufs_ext = [[NSMutableArray alloc] init]; res->cmd_bufs_ext = [[NSMutableArray alloc] init];
res->buf_refs = [[NSMutableArray alloc] init];
res->cmd_buf_last = nil; res->cmd_buf_last = nil;
@@ -206,6 +211,11 @@ void ggml_metal_free(ggml_metal_t ctx) {
[ctx->cmd_bufs_ext removeAllObjects]; [ctx->cmd_bufs_ext removeAllObjects];
[ctx->cmd_bufs_ext release]; [ctx->cmd_bufs_ext release];
@autoreleasepool {
[ctx->buf_refs removeAllObjects];
[ctx->buf_refs release];
}
if (ctx->pipelines_ext) { if (ctx->pipelines_ext) {
ggml_metal_pipelines_free(ctx->pipelines_ext); ggml_metal_pipelines_free(ctx->pipelines_ext);
ctx->pipelines_ext = nil; ctx->pipelines_ext = nil;
@@ -294,6 +304,10 @@ void ggml_metal_synchronize(ggml_metal_t ctx) {
[ctx->cmd_bufs_ext removeAllObjects]; [ctx->cmd_bufs_ext removeAllObjects];
} }
@autoreleasepool {
[ctx->buf_refs removeAllObjects];
}
} }
static struct ggml_metal_buffer_id ggml_metal_get_buffer_id(const struct ggml_tensor * t) { static struct ggml_metal_buffer_id ggml_metal_get_buffer_id(const struct ggml_tensor * t) {
@@ -337,6 +351,8 @@ void ggml_metal_set_tensor_async(ggml_metal_t ctx, struct ggml_tensor * tensor,
[encoder endEncoding]; [encoder endEncoding];
[cmd_buf commit]; [cmd_buf commit];
[ctx->buf_refs addObject:buf_src];
[buf_src release]; [buf_src release];
// do not wait here for completion // do not wait here for completion
@@ -381,6 +397,8 @@ void ggml_metal_get_tensor_async(ggml_metal_t ctx, const struct ggml_tensor * te
[encoder endEncoding]; [encoder endEncoding];
[cmd_buf commit]; [cmd_buf commit];
[ctx->buf_refs addObject:buf_dst];
[buf_dst release]; [buf_dst release];
// do not wait here for completion // do not wait here for completion
+25 -19
View File
@@ -1346,19 +1346,21 @@ ggml_metal_device_t ggml_metal_device_init(int device, int n_devices) {
void ggml_metal_device_free(ggml_metal_device_t dev) { void ggml_metal_device_free(ggml_metal_device_t dev) {
assert(dev != NULL); assert(dev != NULL);
ggml_metal_rsets_free(dev->rsets); @autoreleasepool {
ggml_metal_rsets_free(dev->rsets);
ggml_metal_library_free(dev->library); ggml_metal_library_free(dev->library);
dev->library = NULL; dev->library = NULL;
if (dev->mtl_queue) { if (dev->mtl_queue) {
[dev->mtl_queue release]; [dev->mtl_queue release];
dev->mtl_queue = nil; dev->mtl_queue = nil;
} }
if (dev->mtl_device) { if (dev->mtl_device) {
[dev->mtl_device release]; [dev->mtl_device release];
dev->mtl_device = nil; dev->mtl_device = nil;
}
} }
free(dev); free(dev);
@@ -1446,12 +1448,14 @@ ggml_metal_event_t ggml_metal_device_event_init(ggml_metal_device_t dev) {
} }
void ggml_metal_device_event_free(ggml_metal_device_t dev, ggml_metal_event_t ev) { void ggml_metal_device_event_free(ggml_metal_device_t dev, ggml_metal_event_t ev) {
id<MTLSharedEvent> event = ev->obj; @autoreleasepool {
[event release]; id<MTLSharedEvent> event = ev->obj;
[event release];
free(ev); free(ev);
GGML_UNUSED(dev); GGML_UNUSED(dev);
}
} }
void ggml_metal_device_event_synchronize(ggml_metal_device_t dev, ggml_metal_event_t ev) { void ggml_metal_device_event_synchronize(ggml_metal_device_t dev, ggml_metal_event_t ev) {
@@ -2226,14 +2230,16 @@ ggml_metal_buffer_t ggml_metal_buffer_map(ggml_metal_device_t dev, void * ptr, s
} }
void ggml_metal_buffer_free(ggml_metal_buffer_t buf) { void ggml_metal_buffer_free(ggml_metal_buffer_t buf) {
ggml_metal_device_rsets_rm(buf->dev, buf->rset); @autoreleasepool {
ggml_metal_device_rsets_rm(buf->dev, buf->rset);
for (int i = 0; i < buf->n_buffers; i++) { for (int i = 0; i < buf->n_buffers; i++) {
[buf->buffers[i].metal release]; [buf->buffers[i].metal release];
}
ggml_metal_buffer_rset_free(buf);
} }
ggml_metal_buffer_rset_free(buf);
if (buf->is_shared && buf->owned) { if (buf->is_shared && buf->owned) {
#if TARGET_OS_OSX #if TARGET_OS_OSX
vm_deallocate((vm_map_t)mach_task_self(), (vm_address_t)buf->all_data, buf->all_size); vm_deallocate((vm_map_t)mach_task_self(), (vm_address_t)buf->all_data, buf->all_size);