I know how to create a MTLBuffer and or MTLTexture but how do I free the GPU memory for these resources when they are no longer needed?
2 Answers
MTLBuffer
and MTLTexture
are Objective-C objects and thus reference counted. If you are using automatic reference counting in an Objective-C project or using Metal via Swift, simply ensuring you no longer hold references to the buffer or texture will release any associated hardware resources.
let texture: MTLTexture? = device.newTexture(with: descriptor)
texture = nil // <- resources will be released
One can confirm this by stepping through the associated assembly when assigning nil
to texture
, which first leads us to [MTLDebugTexture dealloc]
MetalTools`-[MTLDebugTexture dealloc]:
...
-> 0x100af569e <+34>: call 0x100af87ee ; symbol stub for: objc_msgSendSuper2
0x100af56a3 <+39>: add rsp, 0x10
0x100af56a7 <+43>: pop rbp
0x100af56a8 <+44>: ret
...and through [MTLToolsObject dealloc]
MetalTools`-[MTLToolsObject dealloc]:
0x100ac6c7a <+0>: push rbp
0x100ac6c7b <+1>: mov rbp, rsp
0x100ac6c7e <+4>: push r14
...
...and through the GeForceMTLDriver
GeForceMTLDriver`___lldb_unnamed_symbol1095$$GeForceMTLDriver:
-> 0x7fffd2e57b14 <+0>: push rbp
0x7fffd2e57b15 <+1>: mov rbp, rsp
All the way, releasing any resources through the various dealloc
methods.

- 5,458
- 1
- 29
- 27
If you are using automatic reference counting, as the accepted answer said, just set nil.
But if you are using manual reference counting, Metal has two kinds of dynamically allocated resources(MTLBuffer && MTLTexture) and you can release them in below way.
id<MTLDevice> m_Device = MTLCreateSystemDefaultDevice();
// allocate Buffer
NSUInteger BufferLength = 100;
id<MTLBuffer> m_Buffer = [m_Device newBufferWithLength:BufferLength options:0];
// allocate Texture
MTLTextureDescriptor *shadowTextureDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatDepth32Float width: 1024 height: 1024 mipmapped: NO];
id<MTLTexture> m_Texture = [m_Device newTextureWithDescriptor:shadowTextureDesc];
// release Buffer
[m_Buffer setPurgeableState:MTLPurgeableStateEmpty];
[m_Buffer release];
// release Texture
[m_Texture setPurgeableState:MTLPurgeableStateEmpty];
[m_Texture release];
About setPurgeableState, you can refer to the link(https://developer.apple.com/documentation/metal/mtlresource/1515898-setpurgeablestate)

- 569
- 8
- 22
-
Id like you to expand on this for other MTL types to make it a better answer. – Ray Garner Apr 08 '19 at 09:59
-
@RayGarner In my opinion, Only MTLBuffer && MTLTexture need to be released(in manual reference counting mode) and the other MTL types are static. Then, they are automatically released when they are out of scope. – 冯剑龙 Apr 08 '19 at 10:43
-
OK what about descriptors that are alloced with new or alloc init. Also is the call to release 100% necessary if you setPurgeableState:MTLPurgeableStateEmpty ? – Ray Garner Apr 10 '19 at 12:55
-
Why is release not enough and you have to set the purgable state to empty? Wouldn't release do it when references get to 0? – rozina Oct 20 '20 at 16:11
-
Of course, you can try it. I only implement the brutal release way. – 冯剑龙 Oct 22 '20 at 00:01
-
I just want to add, that setPurgeableState:MTLPurgeableStateEmpty causes Metal to ignore buffer dependencies. If you happen to have kernels still running or scheduled to run that use the purgeable buffer, you may experience all kinds of weird behaviour. However, if you just call release, the buffer will not be deallocated until all dependent kernels (well, command buffers to be precise) finish executing. – Sergei Kulik Nov 18 '21 at 04:52