Fix memory leaks of system classes during VkInstance and VkQueue creation.
Wrap retrieval of MTLDevice and MTLCommandQueue in an @autoreleasepool.
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 3f2892d..a65f40d 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -23,6 +23,7 @@
- Clarify static linking as the recommended linking approach for *iOS* app store distribution.
- Add request for feedback from people who reject **MoltenVK** to `README.md` document.
- Allow `MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS` build setting to be overridden.
+- Fix memory leaks of system classes during `VkInstance` and `VkQueue` creation.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
index 9ba0bb3..bdbb862 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
@@ -282,17 +282,16 @@
#pragma mark Object Creation
-// Returns a new array containing the MTLDevices available on this system, sorted according to power,
+// Returns an autoreleased array containing the MTLDevices available on this system, sorted according to power,
// with higher power GPU's at the front of the array. This ensures that a lazy app that simply
// grabs the first GPU will get a high-power one by default. If the MVK_CONFIG_FORCE_LOW_POWER_GPU
// env var or build setting is set, the returned array will only include low-power devices.
-// It is the caller's responsibility to release the array when not required anymore.
// If Metal is not supported, returns an empty array.
-static NSArray<id<MTLDevice>>* newAvailableMTLDevicesArray() {
- NSMutableArray* mtlDevs = [NSMutableArray new];
+static NSArray<id<MTLDevice>>* availableMTLDevicesArray() {
+ NSMutableArray* mtlDevs = [NSMutableArray array];
#if MVK_MACOS
- NSArray* rawMTLDevs = MTLCopyAllDevices(); // temp retain
+ NSArray* rawMTLDevs = [MTLCopyAllDevices() autorelease];
if (rawMTLDevs) {
bool forceLowPower = MVK_CONFIG_FORCE_LOW_POWER_GPU;
MVK_SET_FROM_ENV_OR_BUILD_BOOL(forceLowPower, MVK_CONFIG_FORCE_LOW_POWER_GPU);
@@ -322,13 +321,11 @@
}];
}
- [rawMTLDevs release]; // release temp
#endif // MVK_MACOS
#if MVK_IOS
- id<MTLDevice> md = MTLCreateSystemDefaultDevice();
+ id<MTLDevice> md = [MTLCreateSystemDefaultDevice() autorelease];
if (md) { [mtlDevs addObject: md]; }
- [md release];
#endif // MVK_IOS
return mtlDevs; // retained
@@ -359,13 +356,16 @@
mvkGetVulkanVersionString(MVK_VULKAN_API_VERSION).c_str()));
}
- // Populate the array of physical GPU devices
- NSArray<id<MTLDevice>>* mtlDevices = newAvailableMTLDevicesArray(); // temp retain
- _physicalDevices.reserve(mtlDevices.count);
- for (id<MTLDevice> mtlDev in mtlDevices) {
- _physicalDevices.push_back(new MVKPhysicalDevice(this, mtlDev));
+ // Populate the array of physical GPU devices.
+ // This effort creates a number of autoreleased instances of Metal
+ // and other Obj-C classes, so wrap it all in an autorelease pool.
+ @autoreleasepool {
+ NSArray<id<MTLDevice>>* mtlDevices = availableMTLDevicesArray();
+ _physicalDevices.reserve(mtlDevices.count);
+ for (id<MTLDevice> mtlDev in mtlDevices) {
+ _physicalDevices.push_back(new MVKPhysicalDevice(this, mtlDev));
+ }
}
- [mtlDevices release]; // release temp
if (_physicalDevices.empty()) {
setConfigurationResult(reportError(VK_ERROR_INCOMPATIBLE_DRIVER, "Vulkan is not supported on this device. MoltenVK requires Metal, which is not available on this device."));
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
index 9a4dba4..d2cd34b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
@@ -38,9 +38,11 @@
lock_guard<mutex> lock(_qLock);
id<MTLCommandQueue> mtlQ = _mtlQueues[queueIndex];
if ( !mtlQ ) {
- uint32_t maxCmdBuffs = _physicalDevice->getInstance()->getMoltenVKConfiguration()->maxActiveMetalCommandBuffersPerQueue;
- mtlQ = [_physicalDevice->getMTLDevice() newCommandQueueWithMaxCommandBufferCount: maxCmdBuffs]; // retained
- _mtlQueues[queueIndex] = mtlQ;
+ @autoreleasepool { // Catch any autoreleased objects created during MTLCommandQueue creation
+ uint32_t maxCmdBuffs = _physicalDevice->getInstance()->getMoltenVKConfiguration()->maxActiveMetalCommandBuffersPerQueue;
+ mtlQ = [_physicalDevice->getMTLDevice() newCommandQueueWithMaxCommandBufferCount: maxCmdBuffs]; // retained
+ _mtlQueues[queueIndex] = mtlQ;
+ }
}
return mtlQ;
}