Merge pull request #3990 from Flow-Launcher/internalization_memory_leak

Remove old dictionaries references to fix possible memory leak
This commit is contained in:
Jack Ye 2025-09-19 12:41:43 +08:00 committed by GitHub
commit 5d843ecae8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 42 additions and 14 deletions

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@ -14,7 +14,7 @@ using Flow.Launcher.Plugin;
namespace Flow.Launcher.Core.Resource
{
public class Internationalization
public class Internationalization : IDisposable
{
private static readonly string ClassName = nameof(Internationalization);
@ -30,6 +30,7 @@ namespace Flow.Launcher.Core.Resource
private readonly List<string> _languageDirectories = [];
private readonly List<ResourceDictionary> _oldResources = [];
private static string SystemLanguageCode;
private readonly SemaphoreSlim _langChangeLock = new(1, 1);
public Internationalization(Settings settings)
{
@ -185,20 +186,33 @@ namespace Flow.Launcher.Core.Resource
private async Task ChangeLanguageAsync(Language language, bool updateMetadata = true)
{
// Remove old language files and load language
RemoveOldLanguageFiles();
if (language != AvailableLanguages.English)
await _langChangeLock.WaitAsync();
try
{
LoadLanguage(language);
// Remove old language files and load language
RemoveOldLanguageFiles();
if (language != AvailableLanguages.English)
{
LoadLanguage(language);
}
// Change culture info
ChangeCultureInfo(language.LanguageCode);
if (updateMetadata)
{
// Raise event for plugins after culture is set
await Task.Run(UpdatePluginMetadataTranslations);
}
}
// Change culture info
ChangeCultureInfo(language.LanguageCode);
if (updateMetadata)
catch (Exception e)
{
// Raise event for plugins after culture is set
await Task.Run(UpdatePluginMetadataTranslations);
API.LogException(ClassName, $"Failed to change language to <{language.LanguageCode}>", e);
}
finally
{
_langChangeLock.Release();
}
}
@ -257,6 +271,7 @@ namespace Flow.Launcher.Core.Resource
{
dicts.Remove(r);
}
_oldResources.Clear();
}
private void LoadLanguage(Language language)
@ -368,5 +383,15 @@ namespace Flow.Launcher.Core.Resource
}
#endregion
#region IDisposable
public void Dispose()
{
RemoveOldLanguageFiles();
_langChangeLock.Dispose();
}
#endregion
}
}

View file

@ -45,6 +45,7 @@ namespace Flow.Launcher
private static Settings _settings;
private static MainWindow _mainWindow;
private readonly MainViewModel _mainVM;
private readonly Internationalization _internationalization;
// To prevent two disposals running at the same time.
private static readonly object _disposingLock = new();
@ -107,6 +108,7 @@ namespace Flow.Launcher
API = Ioc.Default.GetRequiredService<IPublicAPI>();
_settings.Initialize();
_mainVM = Ioc.Default.GetRequiredService<MainViewModel>();
_internationalization = Ioc.Default.GetRequiredService<Internationalization>();
}
catch (Exception e)
{
@ -193,7 +195,7 @@ namespace Flow.Launcher
Win32Helper.EnableWin32DarkMode(_settings.ColorScheme);
// Initialize language before portable clean up since it needs translations
await Ioc.Default.GetRequiredService<Internationalization>().InitializeLanguageAsync();
await _internationalization.InitializeLanguageAsync();
Ioc.Default.GetRequiredService<Portable>().PreStartCleanUpAfterPortabilityUpdate();
@ -421,6 +423,7 @@ namespace Flow.Launcher
_mainWindow?.Dispatcher.Invoke(_mainWindow.Dispose);
_mainVM?.Dispose();
DialogJump.Dispose();
_internationalization.Dispose();
}
API.LogInfo(ClassName, "End Flow Launcher dispose ----------------------------------------------------");