Retain MVKQueue in MVKQueueSubmission to avoid possible race condition.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
index e9c92ee..33fa317 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
@@ -176,6 +176,8 @@
 					   uint32_t waitSemaphoreCount,
 					   const VkSemaphore* pWaitSemaphores);
 
+	~MVKQueueSubmission() override;
+
 protected:
 	friend class MVKQueue;
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
index 22bd1b2..c76c28f 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
@@ -251,12 +251,18 @@
 									   uint32_t waitSemaphoreCount,
 									   const VkSemaphore* pWaitSemaphores) {
 	_queue = queue;
+	_queue->retain();	// Retain here and release in destructor. See note for MVKQueueCommandBufferSubmission::finish().
+
 	_waitSemaphores.reserve(waitSemaphoreCount);
 	for (uint32_t i = 0; i < waitSemaphoreCount; i++) {
 		_waitSemaphores.push_back(make_pair((MVKSemaphore*)pWaitSemaphores[i], (uint64_t)0));
 	}
 }
 
+MVKQueueSubmission::~MVKQueueSubmission() {
+	_queue->release();
+}
+
 
 #pragma mark -
 #pragma mark MVKQueueCommandBufferSubmission
@@ -390,6 +396,11 @@
 	[mtlCmdBuff release];		// retained
 }
 
+// Be sure to retain() any API objects referenced in this function, and release() them in the
+// destructor (or superclass destructor). It is possible for rare race conditions to result
+// in the app destroying API objects before this function completes execution. For example,
+// this may occur if a GPU semaphore here triggers another submission that triggers a fence,
+// and the app immediately destroys objects. Rare, but it has been encountered.
 void MVKQueueCommandBufferSubmission::finish() {
 
 //	MVKLogDebug("Finishing submission %p. Submission count %u.", this, _subCount--);