@@ -11,6 +11,12 @@ public unsafe class Compressor : IDisposable
11
11
12
12
private int level = DefaultCompressionLevel ;
13
13
14
+ /*
15
+ * We have a finalizer that releases cctx (to prevent memory leaks if Disposed is not called),
16
+ * so we need to delay running the object's finalizer when dealing with cctx inside our methods.
17
+ * For this purpose we use GC.KeepAlive(this)
18
+ * For reference: https://devblogs.microsoft.com/oldnewthing/20100813-00/?p=13153
19
+ */
14
20
private ZSTD_CCtx_s * cctx ;
15
21
16
22
public int Level
@@ -30,20 +36,22 @@ public void SetParameter(ZSTD_cParameter parameter, int value)
30
36
{
31
37
EnsureNotDisposed ( ) ;
32
38
Methods . ZSTD_CCtx_setParameter ( cctx , parameter , value ) . EnsureZstdSuccess ( ) ;
39
+ GC . KeepAlive ( this ) ;
33
40
}
34
41
35
42
public int GetParameter ( ZSTD_cParameter parameter )
36
43
{
37
44
EnsureNotDisposed ( ) ;
38
45
int value ;
39
46
Methods . ZSTD_CCtx_getParameter ( cctx , parameter , & value ) . EnsureZstdSuccess ( ) ;
47
+ GC . KeepAlive ( this ) ;
40
48
return value ;
41
49
}
42
50
43
51
public void LoadDictionary ( byte [ ] dict )
44
52
{
45
53
var dictReadOnlySpan = new ReadOnlySpan < byte > ( dict ) ;
46
- this . LoadDictionary ( dictReadOnlySpan ) ;
54
+ LoadDictionary ( dictReadOnlySpan ) ;
47
55
}
48
56
49
57
public void LoadDictionary ( ReadOnlySpan < byte > dict )
@@ -59,6 +67,7 @@ public void LoadDictionary(ReadOnlySpan<byte> dict)
59
67
fixed ( byte * dictPtr = dict )
60
68
Methods . ZSTD_CCtx_loadDictionary ( cctx , dictPtr , ( nuint ) dict . Length ) . EnsureZstdSuccess ( ) ;
61
69
}
70
+ GC . KeepAlive ( this ) ;
62
71
}
63
72
64
73
public Compressor ( int level = DefaultCompressionLevel )
@@ -96,9 +105,13 @@ public int Wrap(ReadOnlySpan<byte> src, Span<byte> dest)
96
105
EnsureNotDisposed ( ) ;
97
106
fixed ( byte * srcPtr = src )
98
107
fixed ( byte * destPtr = dest )
99
- return ( int ) Methods
108
+ {
109
+ var returnValue = ( int ) Methods
100
110
. ZSTD_compress2 ( cctx , destPtr , ( nuint ) dest . Length , srcPtr , ( nuint ) src . Length )
101
111
. EnsureZstdSuccess ( ) ;
112
+ GC . KeepAlive ( this ) ;
113
+ return returnValue ;
114
+ }
102
115
}
103
116
104
117
public int Wrap ( ArraySegment < byte > src , ArraySegment < byte > dest )
@@ -118,6 +131,7 @@ public bool TryWrap(ReadOnlySpan<byte> src, Span<byte> dest, out int written)
118
131
{
119
132
var returnValue =
120
133
Methods . ZSTD_compress2 ( cctx , destPtr , ( nuint ) dest . Length , srcPtr , ( nuint ) src . Length ) ;
134
+ GC . KeepAlive ( this ) ;
121
135
122
136
if ( returnValue == unchecked ( 0 - ( nuint ) ZSTD_ErrorCode . ZSTD_error_dstSize_tooSmall ) )
123
137
{
@@ -163,7 +177,9 @@ internal nuint CompressStream(ref ZSTD_inBuffer_s input, ref ZSTD_outBuffer_s ou
163
177
fixed ( ZSTD_inBuffer_s * inputPtr = & input )
164
178
fixed ( ZSTD_outBuffer_s * outputPtr = & output )
165
179
{
166
- return Methods . ZSTD_compressStream2 ( cctx , outputPtr , inputPtr , directive ) . EnsureZstdSuccess ( ) ;
180
+ var returnValue = Methods . ZSTD_compressStream2 ( cctx , outputPtr , inputPtr , directive ) . EnsureZstdSuccess ( ) ;
181
+ GC . KeepAlive ( this ) ;
182
+ return returnValue ;
167
183
}
168
184
}
169
185
}
0 commit comments