/
DisposableObject.cs
195 lines (170 loc) · 5.35 KB
/
DisposableObject.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
using System.Runtime.InteropServices;
#pragma warning disable CA1805 // Do not initialize unnecessarily.
namespace OpenCvSharp;
/// <summary>
/// Represents a class which manages its own memory.
/// </summary>
public abstract class DisposableObject : IDisposable
{
/// <summary>
/// Gets or sets a handle which allocates using cvSetData.
/// </summary>
protected GCHandle DataHandle { get; private set; }
private volatile int disposeSignaled = 0;
/// <summary>
/// Gets a value indicating whether this instance has been disposed.
/// </summary>
public bool IsDisposed { get; protected set; }
/// <summary>
/// Gets or sets a value indicating whether you permit disposing this instance.
/// </summary>
public bool IsEnabledDispose { get; set; }
/// <summary>
/// Gets or sets a memory address allocated by AllocMemory.
/// </summary>
protected IntPtr AllocatedMemory { get; set; }
/// <summary>
/// Gets or sets the byte length of the allocated memory
/// </summary>
protected long AllocatedMemorySize { get; set; }
/// <summary>
/// Default constructor
/// </summary>
protected DisposableObject()
: this(true)
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="isEnabledDispose">true if you permit disposing this class by GC</param>
protected DisposableObject(bool isEnabledDispose)
{
IsDisposed = false;
IsEnabledDispose = isEnabledDispose;
AllocatedMemory = IntPtr.Zero;
AllocatedMemorySize = 0;
}
/// <summary>
/// Releases the resources
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases the resources
/// </summary>
/// <param name="disposing">
/// If disposing equals true, the method has been called directly or indirectly by a user's code. Managed and unmanaged resources can be disposed.
/// If false, the method has been called by the runtime from inside the finalizer and you should not reference other objects. Only unmanaged resources can be disposed.
/// </param>
protected virtual void Dispose(bool disposing)
{
#pragma warning disable 420
// http://stackoverflow.com/questions/425132/a-reference-to-a-volatile-field-will-not-be-treated-as-volatile-implications
if (Interlocked.Exchange(ref disposeSignaled, 1) != 0)
{
return;
}
IsDisposed = true;
if (IsEnabledDispose)
{
if (disposing)
{
DisposeManaged();
}
DisposeUnmanaged();
}
}
/// <summary>
/// Destructor
/// </summary>
~DisposableObject()
{
Dispose(false);
}
/// <summary>
/// Releases managed resources
/// </summary>
protected virtual void DisposeManaged()
{
}
/// <summary>
/// Releases unmanaged resources
/// </summary>
protected virtual void DisposeUnmanaged()
{
if (DataHandle.IsAllocated)
{
DataHandle.Free();
}
if (AllocatedMemorySize > 0)
{
GC.RemoveMemoryPressure(AllocatedMemorySize);
AllocatedMemorySize = 0;
}
if (AllocatedMemory != IntPtr.Zero)
{
Marshal.FreeHGlobal(AllocatedMemory);
AllocatedMemory = IntPtr.Zero;
}
}
/// <summary>
/// Pins the object to be allocated by cvSetData.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
// ReSharper disable once InconsistentNaming
protected internal GCHandle AllocGCHandle(object obj)
{
if (obj is null)
throw new ArgumentNullException(nameof(obj));
if (DataHandle.IsAllocated)
DataHandle.Free();
DataHandle = GCHandle.Alloc(obj, GCHandleType.Pinned);
return DataHandle;
}
/// <summary>
/// Allocates the specified size of memory.
/// </summary>
/// <param name="size"></param>
/// <returns></returns>
protected IntPtr AllocMemory(int size)
{
if (size <= 0)
throw new ArgumentOutOfRangeException(nameof(size));
if (AllocatedMemory != IntPtr.Zero)
Marshal.FreeHGlobal(AllocatedMemory);
AllocatedMemory = Marshal.AllocHGlobal(size);
NotifyMemoryPressure(size);
return AllocatedMemory;
}
/// <summary>
/// Notifies the allocated size of memory.
/// </summary>
/// <param name="size"></param>
protected void NotifyMemoryPressure(long size)
{
// マルチスレッド動作時にロックがかかるらしい。いったん廃止
if (!IsEnabledDispose)
return;
if (size == 0)
return;
if (size <= 0)
throw new ArgumentOutOfRangeException(nameof(size));
if (AllocatedMemorySize > 0)
GC.RemoveMemoryPressure(AllocatedMemorySize);
AllocatedMemorySize = size;
GC.AddMemoryPressure(size);
}
/// <summary>
/// If this object is disposed, then ObjectDisposedException is thrown.
/// </summary>
public void ThrowIfDisposed()
{
if (IsDisposed)
throw new ObjectDisposedException(GetType().FullName);
}
}