mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
A GC and dispose correctness pass
This commit is contained in:
parent
508fca2bf7
commit
36d73b82f0
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Concurrency;
|
||||
@ -67,7 +67,7 @@ namespace Wabbajack
|
||||
/// <param name="filterSwitch">On/Off signal of whether to subscribe to source observable</param>
|
||||
/// <param name="valueOnOff">Value to fire when switching off</param>
|
||||
/// <returns>Observable that publishes data from source, if the switch is on.</returns>
|
||||
public static IObservable<T> FilterSwitch<T>(this IObservable<T> source, IObservable<bool> filterSwitch, T valueWhenOff)
|
||||
public static IObservable<T> FlowSwitch<T>(this IObservable<T> source, IObservable<bool> filterSwitch, T valueWhenOff)
|
||||
{
|
||||
return filterSwitch
|
||||
.DistinctUntilChanged()
|
||||
@ -226,5 +226,21 @@ namespace Wabbajack
|
||||
.Select(_ => true)
|
||||
.StartWith(false));
|
||||
}
|
||||
|
||||
public static IObservable<T> DisposeOld<T>(this IObservable<T> source)
|
||||
where T : IDisposable
|
||||
{
|
||||
return source
|
||||
.StartWith(default(T))
|
||||
.Pairwise()
|
||||
.Do(x =>
|
||||
{
|
||||
if (x.Previous != null)
|
||||
{
|
||||
x.Previous.Dispose();
|
||||
}
|
||||
})
|
||||
.Select(x => x.Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ namespace Wabbajack
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
// If Mo2 folder changes and download location is empty, set it for convenience
|
||||
(this).WhenAny(x => x.Mo2Folder)
|
||||
this.WhenAny(x => x.Mo2Folder)
|
||||
.DelayInitial(TimeSpan.FromMilliseconds(100))
|
||||
.Where(x => Directory.Exists(x))
|
||||
.FlowSwitch(
|
||||
|
@ -185,9 +185,19 @@ namespace Wabbajack
|
||||
if (!File.Exists(modListPath)) return default(ModListVM);
|
||||
return new ModListVM(modListPath);
|
||||
})
|
||||
.DisposeOld()
|
||||
.ObserveOnGuiThread()
|
||||
.StartWith(default(ModListVM))
|
||||
.ToProperty(this, nameof(ModList));
|
||||
|
||||
// Force GC collect when modlist changes, just to make sure we clean up any loose large items immediately
|
||||
this.WhenAny(x => x.ModList)
|
||||
.Delay(TimeSpan.FromMilliseconds(50))
|
||||
.Subscribe(x =>
|
||||
{
|
||||
GC.Collect();
|
||||
});
|
||||
|
||||
_LoadingModlist = Observable.Merge(
|
||||
// When active path changes, mark as loading
|
||||
activePath
|
||||
|
@ -21,30 +21,43 @@ namespace Wabbajack
|
||||
|
||||
public ObservableCollectionExtended<ModListMetadataVM> ModLists { get; } = new ObservableCollectionExtended<ModListMetadataVM>();
|
||||
|
||||
public IReactiveCommand RefreshCommand { get; }
|
||||
|
||||
private int missingHashFallbackCounter;
|
||||
|
||||
public ModListGalleryVM(MainWindowVM mainWindowVM)
|
||||
: base(mainWindowVM)
|
||||
{
|
||||
MWVM = mainWindowVM;
|
||||
RefreshCommand = ReactiveCommand.Create(() => { });
|
||||
|
||||
RefreshCommand.StartingExecution()
|
||||
.StartWith(Unit.Default)
|
||||
Observable.Return(Unit.Default)
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.SelectTask(async _ =>
|
||||
{
|
||||
return (await ModlistMetadata.LoadFromGithub())
|
||||
.AsObservableChangeSet(x => x.DownloadMetadata?.Hash ?? $"Fallback{missingHashFallbackCounter++}");
|
||||
})
|
||||
// Unsubscribe and release when not active
|
||||
.FlowSwitch(
|
||||
this.WhenAny(x => x.IsActive),
|
||||
valueWhenOff: Observable.Return(ChangeSet<ModlistMetadata, string>.Empty))
|
||||
// Convert to VM and bind to resulting list
|
||||
.Switch()
|
||||
.ObserveOnGuiThread()
|
||||
.Transform(m => new ModListMetadataVM(this, m))
|
||||
.DisposeMany()
|
||||
.Bind(ModLists)
|
||||
.Subscribe()
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
// Extra GC when navigating away, just to immediately clean up modlist metadata
|
||||
this.WhenAny(x => x.IsActive)
|
||||
.Where(x => !x)
|
||||
.Skip(1)
|
||||
.Delay(TimeSpan.FromMilliseconds(50))
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
GC.Collect();
|
||||
})
|
||||
.DisposeWith(CompositeDisposable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace Wabbajack
|
||||
{
|
||||
public class ModListVM : ViewModel
|
||||
{
|
||||
public ModList SourceModList { get; }
|
||||
public ModList SourceModList { get; private set; }
|
||||
public Exception Error { get; }
|
||||
public string ModListPath { get; }
|
||||
public string Name => SourceModList?.Name;
|
||||
@ -123,5 +123,13 @@ namespace Wabbajack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
// Just drop reference explicitly, as it's large, so it can be GCed
|
||||
// Even if someone is holding a stale reference to the VM
|
||||
this.SourceModList = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,19 +80,20 @@ namespace Wabbajack
|
||||
{
|
||||
if (modList?.SourceModList?.Archives == null)
|
||||
{
|
||||
return Observable.Empty<ModVM>()
|
||||
return Observable.Empty<NexusDownloader.State>()
|
||||
.ToObservableChangeSet(x => x.ModID);
|
||||
}
|
||||
return modList.SourceModList.Archives
|
||||
.Select(m => m.State)
|
||||
.OfType<NexusDownloader.State>()
|
||||
.Select(nexus => new ModVM(nexus))
|
||||
// Shuffle it
|
||||
.Shuffle(_random)
|
||||
.AsObservableChangeSet(x => x.ModID);
|
||||
})
|
||||
// Switch to the new list after every ModList change
|
||||
.Switch()
|
||||
.Transform(nexus => new ModVM(nexus))
|
||||
.DisposeMany()
|
||||
// Filter out any NSFW slides if we don't want them
|
||||
.AutoRefreshOnObservable(slide => this.WhenAny(x => x.ShowNSFW))
|
||||
.Filter(slide => !slide.IsNSFW || ShowNSFW)
|
||||
|
Loading…
Reference in New Issue
Block a user