blob: b0c422d0c0849da4485aa9b79c8bdf664c6625c7 (
plain)
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
|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace System.Runtime.InteropServices
{
/// <summary>
/// Handle for heap memory that allows tracking of capacity and reallocating.
/// </summary>
[System.Security.SecurityCritical]
internal sealed class SafeHeapHandle : SafeBuffer
{
/// <summary>
/// Allocate a buffer of the given size if requested.
/// </summary>
/// <param name="byteLength">Required size in bytes. Must be less than UInt32.MaxValue for 32 bit or UInt64.MaxValue for 64 bit.</param>
/// <exception cref="OutOfMemoryException">Thrown if the requested memory size cannot be allocated.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown if size is greater than the maximum memory size.</exception>
public SafeHeapHandle(ulong byteLength) : base(ownsHandle: true)
{
Resize(byteLength);
}
public override bool IsInvalid
{
[System.Security.SecurityCritical]
get
{ return handle == IntPtr.Zero; }
}
/// <summary>
/// Resize the buffer to the given size if requested.
/// </summary>
/// <param name="byteLength">Required size in bytes. Must be less than UInt32.MaxValue for 32 bit or UInt64.MaxValue for 64 bit.</param>
/// <exception cref="OutOfMemoryException">Thrown if the requested memory size cannot be allocated.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown if size is greater than the maximum memory size.</exception>
public void Resize(ulong byteLength)
{
if (IsClosed) throw new ObjectDisposedException("SafeHeapHandle");
ulong originalLength = 0;
if (handle == IntPtr.Zero)
{
handle = Marshal.AllocHGlobal((IntPtr)byteLength);
}
else
{
originalLength = ByteLength;
// This may or may not be the same handle, may realloc in place. If the
// handle changes Windows will deal with the old handle, trying to free it will
// cause an error.
handle = Marshal.ReAllocHGlobal(pv: handle, cb: (IntPtr)byteLength);
}
if (handle == IntPtr.Zero)
{
// Only real plausible answer
throw new OutOfMemoryException();
}
if (byteLength > originalLength)
{
// Add pressure
ulong addedBytes = byteLength - originalLength;
if (addedBytes > long.MaxValue)
{
GC.AddMemoryPressure(long.MaxValue);
GC.AddMemoryPressure((long)(addedBytes - long.MaxValue));
}
else
{
GC.AddMemoryPressure((long)addedBytes);
}
}
else
{
// Shrank or did nothing, release pressure if needed
RemoveMemoryPressure(originalLength - byteLength);
}
Initialize(byteLength);
}
private void RemoveMemoryPressure(ulong removedBytes)
{
if (removedBytes == 0) return;
if (removedBytes > long.MaxValue)
{
GC.RemoveMemoryPressure(long.MaxValue);
GC.RemoveMemoryPressure((long)(removedBytes - long.MaxValue));
}
else
{
GC.RemoveMemoryPressure((long)removedBytes);
}
}
[System.Security.SecurityCritical]
protected override bool ReleaseHandle()
{
IntPtr handle = this.handle;
this.handle = IntPtr.Zero;
if (handle != IntPtr.Zero)
{
RemoveMemoryPressure(ByteLength);
Marshal.FreeHGlobal(handle);
}
return true;
}
}
}
|