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.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
@ -14,7 +14,7 @@ using Flow.Launcher.Plugin;
namespace Flow.Launcher.Core.Resource namespace Flow.Launcher.Core.Resource
{ {
public class Internationalization public class Internationalization : IDisposable
{ {
private static readonly string ClassName = nameof(Internationalization); private static readonly string ClassName = nameof(Internationalization);
@ -30,6 +30,7 @@ namespace Flow.Launcher.Core.Resource
private readonly List<string> _languageDirectories = []; private readonly List<string> _languageDirectories = [];
private readonly List<ResourceDictionary> _oldResources = []; private readonly List<ResourceDictionary> _oldResources = [];
private static string SystemLanguageCode; private static string SystemLanguageCode;
private readonly SemaphoreSlim _langChangeLock = new(1, 1);
public Internationalization(Settings settings) public Internationalization(Settings settings)
{ {
@ -185,20 +186,33 @@ namespace Flow.Launcher.Core.Resource
private async Task ChangeLanguageAsync(Language language, bool updateMetadata = true) private async Task ChangeLanguageAsync(Language language, bool updateMetadata = true)
{ {
// Remove old language files and load language await _langChangeLock.WaitAsync();
RemoveOldLanguageFiles();
if (language != AvailableLanguages.English) 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);
}
} }
catch (Exception e)
// Change culture info
ChangeCultureInfo(language.LanguageCode);
if (updateMetadata)
{ {
// Raise event for plugins after culture is set API.LogException(ClassName, $"Failed to change language to <{language.LanguageCode}>", e);
await Task.Run(UpdatePluginMetadataTranslations); }
finally
{
_langChangeLock.Release();
} }
} }
@ -257,6 +271,7 @@ namespace Flow.Launcher.Core.Resource
{ {
dicts.Remove(r); dicts.Remove(r);
} }
_oldResources.Clear();
} }
private void LoadLanguage(Language language) private void LoadLanguage(Language language)
@ -368,5 +383,15 @@ namespace Flow.Launcher.Core.Resource
} }
#endregion #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 Settings _settings;
private static MainWindow _mainWindow; private static MainWindow _mainWindow;
private readonly MainViewModel _mainVM; private readonly MainViewModel _mainVM;
private readonly Internationalization _internationalization;
// To prevent two disposals running at the same time. // To prevent two disposals running at the same time.
private static readonly object _disposingLock = new(); private static readonly object _disposingLock = new();
@ -107,6 +108,7 @@ namespace Flow.Launcher
API = Ioc.Default.GetRequiredService<IPublicAPI>(); API = Ioc.Default.GetRequiredService<IPublicAPI>();
_settings.Initialize(); _settings.Initialize();
_mainVM = Ioc.Default.GetRequiredService<MainViewModel>(); _mainVM = Ioc.Default.GetRequiredService<MainViewModel>();
_internationalization = Ioc.Default.GetRequiredService<Internationalization>();
} }
catch (Exception e) catch (Exception e)
{ {
@ -193,7 +195,7 @@ namespace Flow.Launcher
Win32Helper.EnableWin32DarkMode(_settings.ColorScheme); Win32Helper.EnableWin32DarkMode(_settings.ColorScheme);
// Initialize language before portable clean up since it needs translations // Initialize language before portable clean up since it needs translations
await Ioc.Default.GetRequiredService<Internationalization>().InitializeLanguageAsync(); await _internationalization.InitializeLanguageAsync();
Ioc.Default.GetRequiredService<Portable>().PreStartCleanUpAfterPortabilityUpdate(); Ioc.Default.GetRequiredService<Portable>().PreStartCleanUpAfterPortabilityUpdate();
@ -421,6 +423,7 @@ namespace Flow.Launcher
_mainWindow?.Dispatcher.Invoke(_mainWindow.Dispose); _mainWindow?.Dispatcher.Invoke(_mainWindow.Dispose);
_mainVM?.Dispose(); _mainVM?.Dispose();
DialogJump.Dispose(); DialogJump.Dispose();
_internationalization.Dispose();
} }
API.LogInfo(ClassName, "End Flow Launcher dispose ----------------------------------------------------"); API.LogInfo(ClassName, "End Flow Launcher dispose ----------------------------------------------------");