diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 4729a7fe033a016b7392d8c825d421b01254670b..64166ab993542cf22d18949ad3ca0aef49decbd4 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -37,6 +37,10 @@ void Thread::Acquire() {
     ASSERT_MSG(!ShouldWait(), "object unavailable!");
 }
 
+// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
+//               us to simply use a pool index or similar.
+static Kernel::HandleTable wakeup_callback_handle_table;
+
 // Lists all thread ids that aren't deleted/etc.
 static std::vector<SharedPtr<Thread>> thread_list;
 
@@ -93,6 +97,8 @@ void Thread::Stop() {
 
     // Cancel any outstanding wakeup events for this thread
     CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
+    wakeup_callback_handle_table.Close(callback_handle);
+    callback_handle = 0;
 
     // Clean up thread from ready queue
     // This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
@@ -108,6 +114,7 @@ void Thread::Stop() {
     for (auto& wait_object : wait_objects) {
         wait_object->RemoveWaitingThread(this);
     }
+    wait_objects.clear();
 
     Kernel::g_current_process->used_tls_slots[tls_index] = false;
 
@@ -268,10 +275,6 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
     thread->status = THREADSTATUS_WAIT_ARB;
 }
 
-// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
-//               us to simply use a pool index or similar.
-static Kernel::HandleTable wakeup_callback_handle_table;
-
 /**
  * Callback that will wake up the thread it was scheduled for
  * @param thread_handle The handle of the thread that's been awoken
@@ -503,12 +506,16 @@ void ThreadingInit() {
 
     current_thread = nullptr;
     next_thread_id = 1;
-
-    thread_list.clear();
-    ready_queue.clear();
 }
 
 void ThreadingShutdown() {
+    current_thread = nullptr;
+
+    for (auto& t : thread_list) {
+        t->Stop();
+    }
+    thread_list.clear();
+    ready_queue.clear();
 }
 
 } // namespace
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index b364beed926e6808f43b0e373d62cd64dfe2e332..7b6ab4ce015192b18350719147b1ec53289d8ff0 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -406,6 +406,9 @@ void Shutdown() {
     lock = nullptr;
     notification_event = nullptr;
     parameter_event = nullptr;
+
+    next_parameter.object = nullptr;
+
     HLE::Applets::Shutdown();
 }
 
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index fafb43a2fa44e9130994a59a69dd83a5baf5cfeb..a8cb15d6036dabf2665675457ca585ff4d4a9bbb 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -310,4 +310,9 @@ Interface::Interface() {
     Register(FunctionTable);
 }
 
+Interface::~Interface() {
+    semaphore_event = nullptr;
+    interrupt_event = nullptr;
+}
+
 } // namespace
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index 54109b2a9eef4b6208cd5b4dfe9552fabc1a3f0f..b6f611db5c92801c80292b7f6f2911184a49d47e 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -16,6 +16,7 @@ namespace DSP_DSP {
 class Interface : public Service::Interface {
 public:
     Interface();
+    ~Interface() override;
 
     std::string GetPortName() const override {
         return "dsp::DSP";
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 3910d02270b88f9f87d09cee8434af5b8ce4aafc..8b40ba376023d3dd6b13cc2ec1cf60ca1931965d 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -584,7 +584,7 @@ const Interface::FunctionInfo FunctionTable[] = {
 Interface::Interface() {
     Register(FunctionTable);
 
-    g_interrupt_event = 0;
+    g_interrupt_event = nullptr;
 
     using Kernel::MemoryPermission;
     g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
@@ -593,4 +593,9 @@ Interface::Interface() {
     g_thread_id = 0;
 }
 
+Interface::~Interface() {
+    g_interrupt_event = nullptr;
+    g_shared_memory = nullptr;
+}
+
 } // namespace
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index 268089fdd3a64ff3939ef114579f9e0699c44f6e..c89d0a4679d476d0375d625118c04514c04d137f 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -161,6 +161,7 @@ static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrec
 class Interface : public Service::Interface {
 public:
     Interface();
+    ~Interface() override;
 
     std::string GetPortName() const override {
         return "gsp::Gpu";
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp
index 25b01860e5fb4b3963eb8e1d0d951218164b08da..18b22956ff1550aaac0cedbbad03bf60c7d526b0 100644
--- a/src/core/hle/service/nwm_uds.cpp
+++ b/src/core/hle/service/nwm_uds.cpp
@@ -125,4 +125,8 @@ Interface::Interface() {
     Register(FunctionTable);
 }
 
+Interface::~Interface() {
+    handle_event = nullptr;
+}
+
 } // namespace
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h
index 82abdff28ae435f95680d270f560f2e4379ffb44..0ced2359ce9571d00effa66c5dcdeeb16b41c939 100644
--- a/src/core/hle/service/nwm_uds.h
+++ b/src/core/hle/service/nwm_uds.h
@@ -16,6 +16,7 @@ namespace NWM_UDS {
 class Interface : public Service::Interface {
 public:
     Interface();
+    ~Interface() override;
 
     std::string GetPortName() const override {
         return "nwm::UDS";
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index 6c49fa6cf057481705c542965aa9cce370d40337..3b8c7c0e4451b6024bf391829b1394e7aef2e6c8 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -68,4 +68,8 @@ Interface::Interface() {
     Register(FunctionTable);
 }
 
+Interface::~Interface() {
+    event_handle = nullptr;
+}
+
 } // namespace
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h
index 653aba5cb327c2074bdef8ce4b222b8fd7dfef21..96c89b02554205a7c2b02f51988c1cd359be0aeb 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/srv.h
@@ -13,6 +13,7 @@ namespace SRV {
 class Interface : public Service::Interface {
 public:
     Interface();
+    ~Interface() override;
 
     std::string GetPortName() const override {
         return "srv:";
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index e121a54e3304f206e6d6d3121b01b97fcb8e32da..6e7dafaad4a1e218c11c7f4565a8f5698018933d 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -410,4 +410,8 @@ Interface::Interface() {
     Register(FunctionTable);
 }
 
+Interface::~Interface() {
+    completion_event = nullptr;
+}
+
 } // namespace
diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h
index 9454e5aabe376f083147dadfa9e5f6e0b0ef49f1..3965a554563c144c2162cd54c1b572be19339276 100644
--- a/src/core/hle/service/y2r_u.h
+++ b/src/core/hle/service/y2r_u.h
@@ -112,6 +112,7 @@ struct ConversionConfiguration {
 class Interface : public Service::Interface {
 public:
     Interface();
+    ~Interface() override;
 
     std::string GetPortName() const override {
         return "y2r:u";