Remove exposure to leakable instances of NSString, NSArray & NSDictionary.

Reduce creation of autoreleased instances of NSString, NSArray & NSDictionary.
Ensure remaining are covered by deliberate autorelease pools.
diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm
index 7759e48..39ef03b 100644
--- a/Common/MVKOSExtensions.mm
+++ b/Common/MVKOSExtensions.mm
@@ -76,10 +76,12 @@
 #pragma mark Process environment
 
 string mvkGetEnvVar(string varName, bool* pWasFound) {
-	NSDictionary* env = [[NSProcessInfo processInfo] environment];
-	NSString* envStr = env[@(varName.c_str())];
-	if (pWasFound) { *pWasFound = envStr != nil; }
-	return envStr ? envStr.UTF8String : "";
+	@autoreleasepool {
+		NSDictionary*nsEnv = [[NSProcessInfo processInfo] environment];
+		NSString* envStr = nsEnv[@(varName.c_str())];
+		if (pWasFound) { *pWasFound = envStr != nil; }
+		return envStr ? envStr.UTF8String : "";
+	}
 }
 
 int64_t mvkGetEnvVarInt64(string varName, bool* pWasFound) {
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 22a63de..d763dc3 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -31,9 +31,12 @@
 - Fix pipeline cache lookups.
 - Fix race condition between swapchain image destruction and presentation completion callback.
 - Set Metal texture usage to allow texture copy via view.
+- Fix memory leak in debug marker and debug utils labelling.
+- Reduce use of autoreleased Obj-C objects, and ensure those remaining are 
+  covered by deliberate autorelease pools. 
 - `vkCmdCopyImage()` support copying between compressed and uncompressed formats
   and validate that formats are compatible for copying.
-- `vkCmdBufferImageCopy()` fix crash when setting bytes per image in non-arrayed images. 
+- `vkCmdBufferImageCopy()` fix crash when setting bytes per image in non-arrayed images.
 - Document that the functions in `vk_mvk_moltenvk.h` cannot be used with objects 
   retrieved through the *Vulkan SDK Loader and Layers* framework.
 - Update `VK_MVK_MOLTENVK_SPEC_VERSION` to 21.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
index bf86b8f..a7eb94c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
@@ -398,10 +398,12 @@
 #pragma mark Support methods
 
 id<MTLFunction> MVKCommandResourceFactory::getFunctionNamed(const char* funcName) {
-    uint64_t startTime = _device->getPerformanceTimestamp();
-    id<MTLFunction> mtlFunc = [[_mtlLibrary newFunctionWithName: @(funcName)] autorelease];
-    _device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.functionRetrieval, startTime);
-    return mtlFunc;
+	uint64_t startTime = _device->getPerformanceTimestamp();
+	NSString* nsFuncName = [[NSString alloc] initWithUTF8String: funcName];		// temp retained
+	id<MTLFunction> mtlFunc = [[_mtlLibrary newFunctionWithName: nsFuncName] autorelease];
+	[nsFuncName release];	// release temp NSStr
+	_device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.functionRetrieval, startTime);
+	return mtlFunc;
 }
 
 id<MTLFunction> MVKCommandResourceFactory::newMTLFunction(NSString* mslSrcCode, NSString* funcName) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index de49bb3..7c7185c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -372,14 +372,16 @@
     } else {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-        _ioSurface = IOSurfaceCreate((CFDictionaryRef)@{
-                                                        (id)kIOSurfaceWidth: @(_extent.width),
-                                                        (id)kIOSurfaceHeight: @(_extent.height),
-                                                        (id)kIOSurfaceBytesPerElement: @(mvkMTLPixelFormatBytesPerBlock(_mtlPixelFormat)),
-                                                        (id)kIOSurfaceElementWidth: @(mvkMTLPixelFormatBlockTexelSize(_mtlPixelFormat).width),
-                                                        (id)kIOSurfaceElementHeight: @(mvkMTLPixelFormatBlockTexelSize(_mtlPixelFormat).height),
-                                                        (id)kIOSurfaceIsGlobal: @(true),    // Deprecated but needed for interprocess transfers
-                                                        });
+		@autoreleasepool {
+			_ioSurface = IOSurfaceCreate((CFDictionaryRef)@{
+															(id)kIOSurfaceWidth: @(_extent.width),
+															(id)kIOSurfaceHeight: @(_extent.height),
+															(id)kIOSurfaceBytesPerElement: @(mvkMTLPixelFormatBytesPerBlock(_mtlPixelFormat)),
+															(id)kIOSurfaceElementWidth: @(mvkMTLPixelFormatBlockTexelSize(_mtlPixelFormat).width),
+															(id)kIOSurfaceElementHeight: @(mvkMTLPixelFormatBlockTexelSize(_mtlPixelFormat).height),
+															(id)kIOSurfaceIsGlobal: @(true),    // Deprecated but needed for interprocess transfers
+															});
+		}
 #pragma clang diagnostic pop
 
     }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
index aae5cf4..88c41af 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
@@ -252,28 +252,28 @@
 
 #pragma mark Object Creation
 
-// 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.
-// If Metal is not supported, ensure we return an empty array.
-static NSArray<id<MTLDevice>>* getAvailableMTLDevices() {
+// Returns a new 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];
+
 #if MVK_MACOS
-	NSArray* mtlDevs = [MTLCopyAllDevices() autorelease];
-	if ( !mtlDevs ) { return @[]; }
+	NSArray* rawMTLDevs = MTLCopyAllDevices();			// temp retain
+	if (rawMTLDevs) {
+		bool forceLowPower = MVK_CONFIG_FORCE_LOW_POWER_GPU;
+		MVK_SET_FROM_ENV_OR_BUILD_BOOL(forceLowPower, MVK_CONFIG_FORCE_LOW_POWER_GPU);
 
-	bool forceLowPower = MVK_CONFIG_FORCE_LOW_POWER_GPU;
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL(forceLowPower, MVK_CONFIG_FORCE_LOW_POWER_GPU);
-
-	if (forceLowPower) {
-		NSMutableArray* lpDevs = [[NSMutableArray new] autorelease];
-		for (id<MTLDevice> md in mtlDevs) {
-			if (md.isLowPower) { [lpDevs addObject: md]; }
+		// Populate the array of appropriate MTLDevices
+		for (id<MTLDevice> md in rawMTLDevs) {
+			if ( !forceLowPower || md.isLowPower ) { [mtlDevs addObject: md]; }
 		}
-		return lpDevs;
-	} else {
-		return [mtlDevs sortedArrayUsingComparator: ^(id<MTLDevice> md1, id<MTLDevice> md2) {
+
+		// Sort by power
+		[mtlDevs sortUsingComparator: ^(id<MTLDevice> md1, id<MTLDevice> md2) {
 			BOOL md1IsLP = md1.isLowPower;
 			BOOL md2IsLP = md2.isLowPower;
 
@@ -290,14 +290,18 @@
 
 			return md2IsLP ? NSOrderedAscending : NSOrderedDescending;
 		}];
-	}
 
+	}
+	[rawMTLDevs release];								// release temp
 #endif	// MVK_MACOS
 
 #if MVK_IOS
-	id<MTLDevice> mtlDev = MTLCreateSystemDefaultDevice();
-	return mtlDev ? [NSArray arrayWithObject: mtlDev] : @[];
+	id<MTLDevice> md = MTLCreateSystemDefaultDevice();
+	if (md) { [mtlDevs addObject: md]; }
+	[md release];
 #endif	// MVK_IOS
+
+	return mtlDevs;		// retained
 }
 
 MVKInstance::MVKInstance(const VkInstanceCreateInfo* pCreateInfo) : _enabledExtensions(this) {
@@ -326,11 +330,13 @@
 	}
 
 	// Populate the array of physical GPU devices
-	NSArray<id<MTLDevice>>* mtlDevices = getAvailableMTLDevices();
+	NSArray<id<MTLDevice>>* mtlDevices = newAvailableMTLDevicesArray();		// temp retain
 	_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/MVKShaderModule.mm b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm
index b80362b..a243ffb 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm
@@ -49,57 +49,60 @@
 
     if ( !_mtlLibrary ) { return MVKMTLFunctionNull; }
 
-    NSString* mtlFuncName = @(_shaderConversionResults.entryPoint.mtlFunctionName.c_str());
-	MVKDevice* mvkDev = _owner->getDevice();
-    uint64_t startTime = mvkDev->getPerformanceTimestamp();
-    id<MTLFunction> mtlFunc = [[_mtlLibrary newFunctionWithName: mtlFuncName] autorelease];
-    mvkDev->addActivityPerformance(mvkDev->_performanceStatistics.shaderCompilation.functionRetrieval, startTime);
+	id<MTLFunction> mtlFunc = nil;
+	@autoreleasepool {
+		NSString* mtlFuncName = @(_shaderConversionResults.entryPoint.mtlFunctionName.c_str());
+		MVKDevice* mvkDev = _owner->getDevice();
+		uint64_t startTime = mvkDev->getPerformanceTimestamp();
+		mtlFunc = [_mtlLibrary newFunctionWithName: mtlFuncName];	// retained
+		mvkDev->addActivityPerformance(mvkDev->_performanceStatistics.shaderCompilation.functionRetrieval, startTime);
 
-    if (mtlFunc) {
-        // If the Metal device supports shader specialization, and the Metal function expects to be
-        // specialized, populate Metal function constant values from the Vulkan specialization info,
-        // and compiled a specialized Metal function, otherwise simply use the unspecialized Metal function.
-        if (mvkDev->_pMetalFeatures->shaderSpecialization) {
-            NSArray<MTLFunctionConstant*>* mtlFCs = mtlFunc.functionConstantsDictionary.allValues;
-            if (mtlFCs.count) {
-                // The Metal shader contains function constants and expects to be specialized
-                // Populate the Metal function constant values from the Vulkan specialization info.
-                MTLFunctionConstantValues* mtlFCVals = [[MTLFunctionConstantValues new] autorelease];
-                if (pSpecializationInfo) {
-                    // Iterate through the provided Vulkan specialization entries, and populate the
-                    // Metal function constant value that matches the Vulkan specialization constantID.
-                    for (uint32_t specIdx = 0; specIdx < pSpecializationInfo->mapEntryCount; specIdx++) {
-                        const VkSpecializationMapEntry* pMapEntry = &pSpecializationInfo->pMapEntries[specIdx];
-                        NSUInteger mtlFCIndex = pMapEntry->constantID;
-                        MTLFunctionConstant* mtlFC = getFunctionConstant(mtlFCs, mtlFCIndex);
-                        if (mtlFC) {
-                            [mtlFCVals setConstantValue: &(((char*)pSpecializationInfo->pData)[pMapEntry->offset])
-                                                   type: mtlFC.type
-                                                atIndex: mtlFCIndex];
-                        }
-                    }
-                }
+		if (mtlFunc) {
+			// If the Metal device supports shader specialization, and the Metal function expects to be
+			// specialized, populate Metal function constant values from the Vulkan specialization info,
+			// and compiled a specialized Metal function, otherwise simply use the unspecialized Metal function.
+			if (mvkDev->_pMetalFeatures->shaderSpecialization) {
+				NSArray<MTLFunctionConstant*>* mtlFCs = mtlFunc.functionConstantsDictionary.allValues;
+				if (mtlFCs.count) {
+					// The Metal shader contains function constants and expects to be specialized
+					// Populate the Metal function constant values from the Vulkan specialization info.
+					MTLFunctionConstantValues* mtlFCVals = [MTLFunctionConstantValues new];		// temp retain
+					if (pSpecializationInfo) {
+						// Iterate through the provided Vulkan specialization entries, and populate the
+						// Metal function constant value that matches the Vulkan specialization constantID.
+						for (uint32_t specIdx = 0; specIdx < pSpecializationInfo->mapEntryCount; specIdx++) {
+							const VkSpecializationMapEntry* pMapEntry = &pSpecializationInfo->pMapEntries[specIdx];
+							NSUInteger mtlFCIndex = pMapEntry->constantID;
+							MTLFunctionConstant* mtlFC = getFunctionConstant(mtlFCs, mtlFCIndex);
+							if (mtlFC) {
+								[mtlFCVals setConstantValue: &(((char*)pSpecializationInfo->pData)[pMapEntry->offset])
+													   type: mtlFC.type
+													atIndex: mtlFCIndex];
+							}
+						}
+					}
 
-                // Compile the specialized Metal function, and use it instead of the unspecialized Metal function.
-				MVKFunctionSpecializer* fs = new MVKFunctionSpecializer(_owner);
-				mtlFunc = [fs->newMTLFunction(_mtlLibrary, mtlFuncName, mtlFCVals) autorelease];
-				fs->destroy();
-            }
-        }
-    } else {
-        reportError(VK_ERROR_INVALID_SHADER_NV, "Shader module does not contain an entry point named '%s'.", mtlFuncName.UTF8String);
-    }
+					// Compile the specialized Metal function, and use it instead of the unspecialized Metal function.
+					MVKFunctionSpecializer* fs = new MVKFunctionSpecializer(_owner);
+					mtlFunc = fs->newMTLFunction(_mtlLibrary, mtlFuncName, mtlFCVals);	// retained
+					fs->destroy();
+					[mtlFCVals release];		// release temp
+				}
+			}
+		} else {
+			reportError(VK_ERROR_INVALID_SHADER_NV, "Shader module does not contain an entry point named '%s'.", mtlFuncName.UTF8String);
+		}
 
-	// Set the debug name. First try name of shader module, otherwise try name of owner.
-	NSString* dbName = shaderModule-> getDebugName();
-	if ( !dbName ) { dbName = _owner-> getDebugName(); }
-	setLabelIfNotNil(mtlFunc, dbName);
-
+		// Set the debug name. First try name of shader module, otherwise try name of owner.
+		NSString* dbName = shaderModule-> getDebugName();
+		if ( !dbName ) { dbName = _owner-> getDebugName(); }
+		setLabelIfNotNil(mtlFunc, dbName);
+	}
 
 	auto& wgSize = _shaderConversionResults.entryPoint.workgroupSize;
-	return { mtlFunc, _shaderConversionResults, MTLSizeMake(getWorkgroupDimensionSize(wgSize.width, pSpecializationInfo),
-															getWorkgroupDimensionSize(wgSize.height, pSpecializationInfo),
-															getWorkgroupDimensionSize(wgSize.depth, pSpecializationInfo))};
+	return { [mtlFunc autorelease], _shaderConversionResults, MTLSizeMake(getWorkgroupDimensionSize(wgSize.width, pSpecializationInfo),
+																		  getWorkgroupDimensionSize(wgSize.height, pSpecializationInfo),
+																		  getWorkgroupDimensionSize(wgSize.depth, pSpecializationInfo))};
 }
 
 // Returns the MTLFunctionConstant with the specified ID from the specified array of function constants.
@@ -124,7 +127,11 @@
 								   const string& mslSourceCode,
 								   const SPIRVToMSLConversionResults& shaderConversionResults) : _owner(owner) {
 	MVKShaderLibraryCompiler* slc = new MVKShaderLibraryCompiler(_owner);
-	_mtlLibrary = slc->newMTLLibrary(@(mslSourceCode.c_str()));	// retained
+
+	NSString* nsSrc = [[NSString alloc] initWithUTF8String: mslSourceCode.c_str()];	// temp retained
+	_mtlLibrary = slc->newMTLLibrary(nsSrc);	// retained
+	[nsSrc release];	// release temp string
+
 	slc->destroy();
 
 	_shaderConversionResults = shaderConversionResults;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
index 992f1cb..c45c8a6 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
@@ -38,7 +38,9 @@
 	if (_debugName) {
 		size_t imgCnt = _surfaceImages.size();
 		for (size_t imgIdx = 0; imgIdx < imgCnt; imgIdx++) {
-			_surfaceImages[imgIdx]->setDebugName([NSString stringWithFormat: @"%@(%lu)", _debugName, imgIdx].UTF8String);
+			NSString* nsName = [[NSString alloc] initWithFormat: @"%@(%lu)", _debugName, imgIdx];	// temp retain
+			_surfaceImages[imgIdx]->setDebugName(nsName.UTF8String);
+			[nsName release];																		// release temp string
 		}
 	}
 }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm
index 171df2a..f0a1b1c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm
@@ -215,8 +215,10 @@
 	_blocker.wait_for(lock, nanoTimeout, [this]{ return _isCompileDone; });
 
 	if ( !_isCompileDone ) {
-		NSString* errDesc = [NSString stringWithFormat: @"Timeout after %.3f milliseconds. Likely internal Metal compiler error", (double)nanoTimeout.count() / 1e6];
-		_compileError = [[NSError alloc] initWithDomain: @"MoltenVK" code: 1 userInfo: @{NSLocalizedDescriptionKey : errDesc}];	// retained
+		@autoreleasepool {
+			NSString* errDesc = [NSString stringWithFormat: @"Timeout after %.3f milliseconds. Likely internal Metal compiler error", (double)nanoTimeout.count() / 1e6];
+			_compileError = [[NSError alloc] initWithDomain: @"MoltenVK" code: 1 userInfo: @{NSLocalizedDescriptionKey : errDesc}];	// retained
+		}
 	}
 
 	if (_compileError) { handleError(); }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm b/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm
index 6a390b1..109844d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm
@@ -39,7 +39,7 @@
 VkResult MVKVulkanAPIObject::setDebugName(const char* pObjectName) {
 	if (pObjectName) {
 		[_debugName release];
-		_debugName = [[NSString stringWithUTF8String: pObjectName] retain];		// retained
+		_debugName = [[NSString alloc] initWithUTF8String: pObjectName];	// retained
 		propogateDebugName();
 	}
 	return VK_SUCCESS;
diff --git a/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm b/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm
index 156a16e..4ae0de9 100644
--- a/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm
+++ b/MoltenVK/MoltenVK/OS/MVKGPUCapture.mm
@@ -59,8 +59,10 @@
 MVKGPUCaptureScope::MVKGPUCaptureScope(MVKQueue* mvkQueue, const char* purpose) : _queue(mvkQueue) {
 	_mtlQueue = [_queue->getMTLCommandQueue() retain];	// retained
 	if (mvkOSVersion() >= kMinOSVersionMTLCaptureScope) {
+		NSString* nsQLbl = [[NSString alloc] initWithUTF8String: (_queue->getName() + "-" + purpose).c_str()];		// temp retained
 		_mtlCaptureScope = [[MTLCaptureManager sharedCaptureManager] newCaptureScopeWithCommandQueue: _mtlQueue];	// retained
-		_mtlCaptureScope.label = @((_queue->getName() + "-" + purpose).c_str());
+		_mtlCaptureScope.label = nsQLbl;
+		[nsQLbl release];																							// release temp
 	}
 }
 
diff --git a/MoltenVK/MoltenVK/Utility/MVKWatermark.mm b/MoltenVK/MoltenVK/Utility/MVKWatermark.mm
index db7740c..aa06d51 100644
--- a/MoltenVK/MoltenVK/Utility/MVKWatermark.mm
+++ b/MoltenVK/MoltenVK/Utility/MVKWatermark.mm
@@ -304,9 +304,11 @@
 // Initialize the shader functions for rendering the watermark
 void MVKWatermark::initShaders(const char* mslSourceCode) {
     NSError* err = nil;
-    id<MTLLibrary> mtlLib = [[_mtlDevice newLibraryWithSource: @(mslSourceCode)
+	NSString* nsSrc = [[NSString alloc] initWithUTF8String: mslSourceCode];	// temp retained
+    id<MTLLibrary> mtlLib = [[_mtlDevice newLibraryWithSource: nsSrc
                                                       options: nil
                                                         error: &err] autorelease];
+	[nsSrc release];														// release temp string
 	MVKAssert( !err, "Could not compile watermark shaders (Error code %li):\n%s", (long)err.code, err.localizedDescription.UTF8String);
 
     _mtlFunctionVertex = [mtlLib newFunctionWithName: @"watermarkVertex"];          // retained