Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions src/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -598,26 +598,43 @@ private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
/// </summary>
public static void ReleaseMemory()
{
// Garbage Collector
try
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
}
catch
{
// ignored
}
ReleaseMemory
(
ReleaseMemoryMode.Combined,
() =>
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
},
() => NativeMethods.EmptyWorkingSet(Process.GetCurrentProcess().Handle)
);
}

// Optimize App Working Set
try
internal static void ReleaseMemory(ReleaseMemoryMode mode, Action collectGarbage, Action trimWorkingSet)
{
if (mode == ReleaseMemoryMode.GCOnly || mode == ReleaseMemoryMode.Combined)
{
NativeMethods.EmptyWorkingSet(Process.GetCurrentProcess().Handle);
try
{
collectGarbage();
}
catch
{
// ignored
}
}
catch (Exception)

if (mode == ReleaseMemoryMode.TrimOnly || mode == ReleaseMemoryMode.Combined)
{
// ignored
try
{
trimWorkingSet();
}
catch
{
// ignored
}
}
}

Expand Down
68 changes: 68 additions & 0 deletions src/Core/OptimizationTiming.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;

namespace WinMemoryCleaner
{
/// <summary>
/// Provides a deterministic seam for measuring optimization completion.
/// </summary>
internal sealed class OptimizationTiming
{
private readonly Func<TimeSpan> _clock;
private readonly TimeSpan _startedAt;

internal OptimizationTiming(Func<TimeSpan> clock)
{
if (clock == null)
throw new ArgumentNullException("clock");

_clock = clock;
_startedAt = _clock();
}

internal TimeSpan FinalAppReleaseDuration { get; private set; }

internal TimeSpan Elapsed
{
get { return _clock().Subtract(_startedAt); }
}

internal TimeSpan Measure(Action stage)
{
if (stage == null)
throw new ArgumentNullException("stage");

var startedAt = _clock();

stage();

return _clock().Subtract(startedAt);
}

internal TimeSpan Complete(Action finalAppRelease)
{
if (finalAppRelease == null)
throw new ArgumentNullException("finalAppRelease");

var finalAppReleaseStartedAt = _clock();

try
{
finalAppRelease();
}
finally
{
FinalAppReleaseDuration = _clock().Subtract(finalAppReleaseStartedAt);
}

return Elapsed;
}
}

internal enum ReleaseMemoryMode
{
None,
GCOnly,
TrimOnly,
Combined
}
}
53 changes: 20 additions & 33 deletions src/Service/ComputerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
if (areas == Enums.Memory.Areas.None)
return;

var errorRuntime = new TimeSpan();
var infoRuntime = new TimeSpan();
var optimizationReason = reason.GetString();
var stopwatch = new Stopwatch();
var totalStopwatch = Stopwatch.StartNew();
var optimizationTiming = new OptimizationTiming(() => totalStopwatch.Elapsed);
var value = (byte)0;

var error = new LogOptimizationData { Reason = optimizationReason };
Expand All @@ -178,8 +178,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Name = Localizer.String.WorkingSet,
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture))
});

infoRuntime = infoRuntime.Add(stopwatch.Elapsed);
}
catch (Exception e)
{
Expand All @@ -189,8 +187,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture)),
Error = e.GetMessage()
});

errorRuntime = errorRuntime.Add(stopwatch.Elapsed);
}
}

Expand All @@ -214,8 +210,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Name = Localizer.String.SystemFileCache,
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture))
});

infoRuntime = infoRuntime.Add(stopwatch.Elapsed);
}
catch (Exception e)
{
Expand All @@ -225,8 +219,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture)),
Error = e.GetMessage()
});

errorRuntime = errorRuntime.Add(stopwatch.Elapsed);
}
}

Expand All @@ -250,8 +242,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Name = Localizer.String.ModifiedPageList,
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture))
});

infoRuntime = infoRuntime.Add(stopwatch.Elapsed);
}
catch (Exception e)
{
Expand All @@ -261,8 +251,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture)),
Error = e.GetMessage()
});

errorRuntime = errorRuntime.Add(stopwatch.Elapsed);
}
}

Expand All @@ -289,8 +277,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Name = standbyList,
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture))
});

infoRuntime = infoRuntime.Add(stopwatch.Elapsed);
}
catch (Exception e)
{
Expand All @@ -300,8 +286,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture)),
Error = e.GetMessage()
});

errorRuntime = errorRuntime.Add(stopwatch.Elapsed);
}
}

Expand All @@ -325,8 +309,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Name = Localizer.String.CombinedPageList,
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture))
});

infoRuntime = infoRuntime.Add(stopwatch.Elapsed);
}
catch (Exception e)
{
Expand All @@ -336,8 +318,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture)),
Error = e.GetMessage()
});

errorRuntime = errorRuntime.Add(stopwatch.Elapsed);
}
}

Expand All @@ -361,8 +341,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Name = Localizer.String.RegistryCache,
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture))
});

infoRuntime = infoRuntime.Add(stopwatch.Elapsed);
}
catch (Exception e)
{
Expand All @@ -372,8 +350,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture)),
Error = e.GetMessage()
});

errorRuntime = errorRuntime.Add(stopwatch.Elapsed);
}
}

Expand All @@ -397,8 +373,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Name = Localizer.String.ModifiedFileCache,
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture))
});

infoRuntime = infoRuntime.Add(stopwatch.Elapsed);
}
catch (Exception e)
{
Expand All @@ -408,8 +382,6 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", stopwatch.Elapsed.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture)),
Error = e.GetMessage()
});

errorRuntime = errorRuntime.Add(stopwatch.Elapsed);
}
}

Expand All @@ -422,27 +394,42 @@ public void Optimize(Enums.Memory.Optimization.Reason reason, Enums.Memory.Areas
OnOptimizeProgressUpdate(value, Localizer.String.GarbageCollector);
}

App.ReleaseMemory();
optimizationTiming.Complete(App.ReleaseMemory);

var appReleaseTiming = new LogOptimizationDataMemoryArea
{
Name = Localizer.String.GarbageCollector,
Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", optimizationTiming.FinalAppReleaseDuration.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture))
};

// Include final-stage timing without turning failed native work into a success notification.
if (info.MemoryAreas.Any())
info.MemoryAreas.Add(appReleaseTiming);

if (error.MemoryAreas.Any())
error.MemoryAreas.Add(appReleaseTiming);
}
catch
{
// ignored
}

var totalRuntime = optimizationTiming.Elapsed;

// Log
try
{
// Info
if (info.MemoryAreas.Any())
{
info.Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", infoRuntime.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture));
info.Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", totalRuntime.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture));

Logger.Log(new Log(Enums.Log.Levels.Information, Localizer.String.MemoryOptimized, info));
}
// Error
if (error.MemoryAreas.Any())
{
error.Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", errorRuntime.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture));
error.Duration = string.Format(Localizer.Culture, "{0:0.0} {1}", totalRuntime.TotalSeconds, Localizer.String.Seconds.ToLower(Localizer.Culture));

Logger.Log(new Log(Enums.Log.Levels.Error, Localizer.String.Invalid, error));
}
Expand Down
Loading
Loading