22// Licensed under the Apache License, Version 2.0.
33
44using System ;
5- using System . Collections . Generic ;
6- using System . Diagnostics ;
75using System . Threading ;
86using SixLabors . ImageSharp . Diagnostics ;
97using Xunit ;
@@ -12,53 +10,68 @@ namespace SixLabors.ImageSharp.Drawing.Tests
1210{
1311 public static class MemoryAllocatorValidator
1412 {
15- private static List < string > traces = new List < string > ( ) ;
13+ private static readonly AsyncLocal < TestMemoryDiagnostics > LocalInstance = new ( ) ;
1614
17- public static void MonitorStackTraces ( ) => MemoryDiagnostics . UndisposedAllocation += MemoryDiagnostics_UndisposedAllocation ;
15+ public static bool MonitoringAllocations => LocalInstance . Value != null ;
1816
19- public static List < string > GetStackTraces ( )
17+ static MemoryAllocatorValidator ( )
2018 {
21- GC . Collect ( ) ;
22- GC . WaitForPendingFinalizers ( ) ;
23- return traces ;
19+ MemoryDiagnostics . MemoryAllocated += MemoryDiagnostics_MemoryAllocated ;
20+ MemoryDiagnostics . MemoryReleased += MemoryDiagnostics_MemoryReleased ;
2421 }
2522
26- private static void MemoryDiagnostics_UndisposedAllocation ( string allocationStackTrace )
23+ private static void MemoryDiagnostics_MemoryReleased ( )
2724 {
28- lock ( traces )
25+ TestMemoryDiagnostics backing = LocalInstance . Value ;
26+ if ( backing != null )
2927 {
30- traces . Add ( allocationStackTrace ) ;
28+ backing . TotalRemainingAllocated -- ;
3129 }
3230 }
3331
34- public static TestMemoryAllocatorDisposable MonitorAllocations ( )
32+ private static void MemoryDiagnostics_MemoryAllocated ( )
3533 {
36- MemoryDiagnostics . Current = new ( ) ;
37- return new TestMemoryAllocatorDisposable ( ) ;
34+ TestMemoryDiagnostics backing = LocalInstance . Value ;
35+ if ( backing != null )
36+ {
37+ backing . TotalAllocated ++ ;
38+ backing . TotalRemainingAllocated ++ ;
39+ }
40+ }
41+
42+ public static TestMemoryDiagnostics MonitorAllocations ( )
43+ {
44+ var diag = new TestMemoryDiagnostics ( ) ;
45+ LocalInstance . Value = diag ;
46+ return diag ;
3847 }
3948
40- public static void StopMonitoringAllocations ( ) => MemoryDiagnostics . Current = null ;
49+ public static void StopMonitoringAllocations ( ) => LocalInstance . Value = null ;
50+
51+ public static void ValidateAllocations ( int expectedAllocationCount = 0 )
52+ => LocalInstance . Value ? . Validate ( expectedAllocationCount ) ;
4153
42- public static void ValidateAllocation ( int max = 0 )
54+ public class TestMemoryDiagnostics : IDisposable
4355 {
44- var count = MemoryDiagnostics . TotalUndisposedAllocationCount ;
56+ public int TotalAllocated { get ; set ; }
4557
46- var pass = count <= max ;
47- Assert . True ( pass , $ "Expected a max of { max } undisposed buffers but found { count } ") ;
58+ public int TotalRemainingAllocated { get ; set ; }
4859
49- if ( count > 0 )
60+ public void Validate ( int expectedAllocationCount )
5061 {
51- Debug . WriteLine ( "We should have Zero undisposed memory allocations." ) ;
62+ var count = this . TotalRemainingAllocated ;
63+ var pass = expectedAllocationCount == count ;
64+ Assert . True ( pass , $ "Expected a { expectedAllocationCount } undisposed buffers but found { count } ") ;
5265 }
53- }
5466
55- public struct TestMemoryAllocatorDisposable : IDisposable
56- {
5767 public void Dispose ( )
58- => StopMonitoringAllocations ( ) ;
59-
60- public void Validate ( int maxAllocations = 0 )
61- => ValidateAllocation ( maxAllocations ) ;
68+ {
69+ this . Validate ( 0 ) ;
70+ if ( LocalInstance . Value == this )
71+ {
72+ StopMonitoringAllocations ( ) ;
73+ }
74+ }
6275 }
6376 }
6477}
0 commit comments