Merge pull request #7227 from vonchenplus/fix_memory_leak_v2

Fix memory leak v2
This commit is contained in:
bunnei 2021-11-01 20:11:30 -07:00 committed by GitHub
commit b118fa8698
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 54 additions and 24 deletions

View File

@ -83,12 +83,6 @@ FileSys::StorageId GetStorageIdForFrontendSlot(
} }
} }
void KProcessDeleter(Kernel::KProcess* process) {
process->Destroy();
}
using KProcessPtr = std::unique_ptr<Kernel::KProcess, decltype(&KProcessDeleter)>;
} // Anonymous namespace } // Anonymous namespace
FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
@ -261,11 +255,10 @@ struct System::Impl {
} }
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
main_process = KProcessPtr{Kernel::KProcess::Create(system.Kernel()), KProcessDeleter}; auto main_process = Kernel::KProcess::Create(system.Kernel());
ASSERT(Kernel::KProcess::Initialize(main_process.get(), system, "main", ASSERT(Kernel::KProcess::Initialize(main_process, system, "main",
Kernel::KProcess::ProcessType::Userland) Kernel::KProcess::ProcessType::Userland)
.IsSuccess()); .IsSuccess());
main_process->Open();
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
if (load_result != Loader::ResultStatus::Success) { if (load_result != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result); LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
@ -275,7 +268,7 @@ struct System::Impl {
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
} }
AddGlueRegistrationForProcess(*app_loader, *main_process); AddGlueRegistrationForProcess(*app_loader, *main_process);
kernel.MakeCurrentProcess(main_process.get()); kernel.MakeCurrentProcess(main_process);
kernel.InitializeCores(); kernel.InitializeCores();
// Initialize cheat engine // Initialize cheat engine
@ -340,8 +333,6 @@ struct System::Impl {
kernel.Shutdown(); kernel.Shutdown();
memory.Reset(); memory.Reset();
applet_manager.ClearAll(); applet_manager.ClearAll();
// TODO: The main process should be freed based on KAutoObject ref counting.
main_process.reset();
LOG_DEBUG(Core, "Shutdown OK"); LOG_DEBUG(Core, "Shutdown OK");
} }
@ -403,7 +394,6 @@ struct System::Impl {
std::unique_ptr<Tegra::GPU> gpu_core; std::unique_ptr<Tegra::GPU> gpu_core;
std::unique_ptr<Hardware::InterruptManager> interrupt_manager; std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
std::unique_ptr<Core::DeviceMemory> device_memory; std::unique_ptr<Core::DeviceMemory> device_memory;
KProcessPtr main_process{nullptr, KProcessDeleter};
Core::Memory::Memory memory; Core::Memory::Memory memory;
CpuManager cpu_manager; CpuManager cpu_manager;
std::atomic_bool is_powered_on{}; std::atomic_bool is_powered_on{};

View File

@ -56,6 +56,7 @@ bool KHandleTable::Remove(Handle handle) {
} }
// Close the object. // Close the object.
kernel.UnregisterInUseObject(obj);
obj->Close(); obj->Close();
return true; return true;
} }

View File

@ -434,11 +434,6 @@ void KProcess::PrepareForTermination() {
} }
void KProcess::Finalize() { void KProcess::Finalize() {
// Release memory to the resource limit.
if (resource_limit != nullptr) {
resource_limit->Close();
}
// Finalize the handle table and close any open handles. // Finalize the handle table and close any open handles.
handle_table.Finalize(); handle_table.Finalize();
@ -460,6 +455,12 @@ void KProcess::Finalize() {
} }
} }
// Release memory to the resource limit.
if (resource_limit != nullptr) {
resource_limit->Close();
resource_limit = nullptr;
}
// Perform inherited finalization. // Perform inherited finalization.
KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize(); KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize();
} }

View File

@ -91,12 +91,6 @@ struct KernelCore::Impl {
} }
void Shutdown() { void Shutdown() {
// Shutdown all processes.
if (current_process) {
current_process->Finalize();
current_process->Close();
current_process = nullptr;
}
process_list.clear(); process_list.clear();
// Close all open server ports. // Close all open server ports.
@ -170,6 +164,24 @@ struct KernelCore::Impl {
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
next_host_thread_id = Core::Hardware::NUM_CPU_CORES; next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
// Close kernel objects that were not freed on shutdown
{
std::lock_guard lk(registered_in_use_objects_lock);
if (registered_in_use_objects.size()) {
for (auto& object : registered_in_use_objects) {
object->Close();
}
registered_in_use_objects.clear();
}
}
// Shutdown all processes.
if (current_process) {
current_process->Finalize();
current_process->Close();
current_process = nullptr;
}
// Track kernel objects that were not freed on shutdown // Track kernel objects that were not freed on shutdown
{ {
std::lock_guard lk(registered_objects_lock); std::lock_guard lk(registered_objects_lock);
@ -714,9 +726,11 @@ struct KernelCore::Impl {
std::unordered_set<KServerPort*> server_ports; std::unordered_set<KServerPort*> server_ports;
std::unordered_set<KServerSession*> server_sessions; std::unordered_set<KServerSession*> server_sessions;
std::unordered_set<KAutoObject*> registered_objects; std::unordered_set<KAutoObject*> registered_objects;
std::unordered_set<KAutoObject*> registered_in_use_objects;
std::mutex server_ports_lock; std::mutex server_ports_lock;
std::mutex server_sessions_lock; std::mutex server_sessions_lock;
std::mutex registered_objects_lock; std::mutex registered_objects_lock;
std::mutex registered_in_use_objects_lock;
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
std::vector<Kernel::PhysicalCore> cores; std::vector<Kernel::PhysicalCore> cores;
@ -928,6 +942,16 @@ void KernelCore::UnregisterKernelObject(KAutoObject* object) {
impl->registered_objects.erase(object); impl->registered_objects.erase(object);
} }
void KernelCore::RegisterInUseObject(KAutoObject* object) {
std::lock_guard lk(impl->registered_in_use_objects_lock);
impl->registered_in_use_objects.insert(object);
}
void KernelCore::UnregisterInUseObject(KAutoObject* object) {
std::lock_guard lk(impl->registered_in_use_objects_lock);
impl->registered_in_use_objects.erase(object);
}
bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
return port != impl->named_ports.cend(); return port != impl->named_ports.cend();
} }

View File

@ -204,6 +204,14 @@ public:
/// destroyed during the current emulation session. /// destroyed during the current emulation session.
void UnregisterKernelObject(KAutoObject* object); void UnregisterKernelObject(KAutoObject* object);
/// Registers kernel objects with guest in use state, this is purely for close
/// after emulation has been shutdown.
void RegisterInUseObject(KAutoObject* object);
/// Unregisters a kernel object previously registered with RegisterInUseObject when it was
/// destroyed during the current emulation session.
void UnregisterInUseObject(KAutoObject* object);
/// Determines whether or not the given port is a valid named port. /// Determines whether or not the given port is a valid named port.
bool IsValidNamedPort(NamedPortTable::const_iterator port) const; bool IsValidNamedPort(NamedPortTable::const_iterator port) const;

View File

@ -427,11 +427,15 @@ static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr ha
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
num_handles), num_handles),
ResultInvalidHandle); ResultInvalidHandle);
for (const auto& obj : objs) {
kernel.RegisterInUseObject(obj);
}
} }
// Ensure handles are closed when we're done. // Ensure handles are closed when we're done.
SCOPE_EXIT({ SCOPE_EXIT({
for (u64 i = 0; i < num_handles; ++i) { for (u64 i = 0; i < num_handles; ++i) {
kernel.UnregisterInUseObject(objs[i]);
objs[i]->Close(); objs[i]->Close();
} }
}); });
@ -1561,6 +1565,7 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
// If we succeeded, persist a reference to the thread. // If we succeeded, persist a reference to the thread.
thread->Open(); thread->Open();
system.Kernel().RegisterInUseObject(thread.GetPointerUnsafe());
return ResultSuccess; return ResultSuccess;
} }
@ -1576,6 +1581,7 @@ static void ExitThread(Core::System& system) {
auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
system.GlobalSchedulerContext().RemoveThread(current_thread); system.GlobalSchedulerContext().RemoveThread(current_thread);
current_thread->Exit(); current_thread->Exit();
system.Kernel().UnregisterInUseObject(current_thread);
} }
static void ExitThread32(Core::System& system) { static void ExitThread32(Core::System& system) {