好的,你所有的ASP.NET专家:我用反射器来研究ASP.NET Cache实现(它位于HttpRuntime.Cache和HttpContext.Current.Cache)使用Hashtable内部来保持缓存.
但是,数据存储在非托管内存中.这很奇怪,因为我无法看到任何数据存储在非托管内存中.但是,编写一个非常简单的Web应用程序,将一大块字节数组插入缓存中,我们可以看到:

所以基本上我多次调用应用程序(每次增加1000x请求,每个将64KB空缓冲区byte []放入缓存).因此,增长最多的是私有字节(总内存)而不是所有堆中的字节(托管内存).但是我期望托管内存与总内存一致增长,因为我使用Hashtable将对象添加到托管堆.
你能解释一下这种行为吗?
正如Simon所说,所有堆中的字节值仅在垃圾收集后更改 - 我更改了代码以引发垃圾收集并更新计数器.Gen 2堆内存的增加与添加的内存量完全相同.但是,非托管内存仍然高得多.在此示例中,堆2仅为96MB,而总内存为231 MB.

我通过我的应用程序分配一些非托管内存Marshal.AllocHGlobal.然后,我将一组字节复制到此位置,并将生成的内存段转换为a,struct然后再通过释放内存Marshal.FreeHGlobal.
这是方法:
public static T Deserialize<T>(byte[] messageBytes, int start, int length)
where T : struct
{
if (start + length > messageBytes.Length)
throw new ArgumentOutOfRangeException();
int typeSize = Marshal.SizeOf(typeof(T));
int bytesToCopy = Math.Min(typeSize, length);
IntPtr targetBytes = Marshal.AllocHGlobal(typeSize);
Marshal.Copy(messageBytes, start, targetBytes, bytesToCopy);
if (length < typeSize)
{
// Zero out additional bytes at the end of the struct
}
T item = (T)Marshal.PtrToStructure(targetBytes, typeof(T));
Marshal.FreeHGlobal(targetBytes);
return item;
}
Run Code Online (Sandbox Code Playgroud)
这在大多数情况下都有效,但是如果我的字节数少于需求的大小struct,那么"随机"值将分配给最后的字段(我LayoutKind.Sequential在目标结构上使用).我想尽可能有效地将这些悬挂的区域归零.
对于上下文,此代码对从Linux上的C++发送的高频多播消息进行反序列化. …
更新:现在有一个被接受的答案"有效".你应该永远,永远,永远,永远使用它.曾经.
首先让我先说明我是一名游戏开发者.想要这样做有一个合法的 - 如果非常不寻常 - 与性能相关的原因.
假设我有一个像这样的C#类:
class Foo
{
public int a, b, c;
public void MyMethod(int d) { a = d; b = d; c = a + b; }
}
Run Code Online (Sandbox Code Playgroud)
没有什么花哨.请注意,它是仅包含值类型的引用类型.
在托管代码中,我希望有这样的东西:
Foo foo;
foo = Voodoo.NewInUnmanagedMemory<Foo>(); // <- ???
foo.MyMethod(1);
Run Code Online (Sandbox Code Playgroud)
这个功能NewInUnmanagedMemory会是什么样的?如果无法在C#中完成,可以在IL中完成吗?(或者可能是C++/CLI?)
基本上:有没有办法 - 无论多么苛刻 - 将一些完全任意的指针转换为对象引用.并且 - 没有使CLR爆炸 - 该死的后果.
(提出问题的另一种方法是:"我想为C#实现自定义分配器")
这导致了后续问题:当面对指向托管内存之外的引用时,垃圾收集器会做什么(特定于实现,如果需要)?
并且,与此相关,如果Foo将引用作为成员字段会发生什么?如果它指向托管内存怎么办?如果它只指向非托管内存中分配的其他对象怎么办?
最后,如果这是不可能的:为什么?
更新:到目前为止,这是"缺失的部分":
#1:如何将IntPtr对象转换为对象引用?虽然无法验证的IL可能是可能的(见评论).到目前为止,我没有运气.该框架似乎非常小心,以防止这种情况发生.
(能够在运行时获取非blittable托管类型的大小和布局信息也很好.同样,框架试图使这变得不可能.)
#2:假设问题可以解决 - 当GC遇到指向GC堆外部的对象引用时,它会做什么?它崩溃了吗?Anton Tykhyy 在他的回答中猜测它会.考虑到框架对于防止#1的谨慎程度,它似乎很可能.确认这一点的东西会很好. …
我正在使用FFmpeg库以最小的延迟(MediaElement无法处理的东西)通过UDP接收和解码H.264/MPEG-TS .
在专用的FFmpeg线程上,我正在拉PixelFormats.Bgr32视频帧进行显示.我已经尝试过InteropBitmap:
_section = CreateFileMapping(INVALID_HANDLE_VALUE, IntPtr.Zero, PAGE_READWRITE, 0, size, null);
_buffer = MapViewOfFile(_section, FILE_MAP_ALL_ACCESS, 0, 0, size);
Dispatcher.Invoke((Action)delegate()
{
_interopBitmap = (InteropBitmap)Imaging.CreateBitmapSourceFromMemorySection(_section, width, height, PixelFormats.Bgr32, (int)size / height, 0);
this.Source = _interopBitmap;
});
Run Code Online (Sandbox Code Playgroud)
然后每帧更新:
Dispatcher.Invoke((Action)delegate()
{
_interopBitmap.Invalidate();
});
Run Code Online (Sandbox Code Playgroud)
但性能非常差(跳帧,高CPU使用率等).
我也试过WriteableBitmap:FFmpeg将帧放在_writeableBitmap.BackBuffer和每帧更新:
Dispatcher.Invoke((Action)delegate()
{
_writeableBitmap.Lock();
});
try
{
ret = FFmpegInvoke.sws_scale(...);
}
finally
{
Dispatcher.Invoke((Action)delegate()
{
_writeableBitmap.AddDirtyRect(_rect);
_writeableBitmap.Unlock();
});
}
Run Code Online (Sandbox Code Playgroud)
遇到几乎相同的性能问题(使用各种DispatcherPriority测试).
任何帮助将不胜感激.
通过引入的Memory,Span并且ArraySegment在C#7.2,我想知道如果我可以代表一个非托管数组作为枚举对象,即生活在堆上.
后一个要求排除了Span,它基本上实现了我想要的东西:例如
unsafe { bytes = new Span<byte>((byte*)ptr + (index * Width), Width);
Run Code Online (Sandbox Code Playgroud)
是否可以用ArraySegment或做同样的事情Memory?他们的构造函数只接受byte[],也许有某种方法可以欺骗C#byte*而不是传递byte[]?
从解锁的Bitmap非托管内存直接写入和读取是否可以?
在我解锁Bitmap后,我可以继续使用BitmapData吗?我做了一个测试应用程序,我可以在鼠标位置读取PictureBox的Bitmap像素,而另一个线程正在将像素写入同一个Bitmap.
编辑1:正如Boing他在回答中指出的那样:"Scan0没有指向Bitmap对象的实际像素数据;而是指向一个临时缓冲区,它代表Bitmap对象中像素数据的一部分." 来自MSDN.
但是一旦我得到了Scan0,我就可以读取/写入Bitmap而无需Lockbits或UnlockBits!我在一个帖子里做了很多次.相对于MSDN,它不应该发生,因为Scan0指向位图数据的COPY!好吧,在C#中,所有测试表明它不是副本.在C++中,我不知道它是否正常工作.
编辑2:使用旋转方法有时会使操作系统释放位图像素数据副本.结论,it is not safe to read/write an unlocked Bitmap Scan0.谢谢Boing的回答和评论!
下面是我如何获取BitmapData并读取和写入像素值.
/// <summary>
/// Locks and unlocks the Bitmap to get the BitmapData.
/// </summary>
/// <param name="bmp">Bitmap</param>
/// <returns>BitmapData</returns>
public static BitmapData GetBitmapData(Bitmap bmp)
{
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
bmp.UnlockBits(bmpData);
return bmpData;
}
/// <summary>
/// Get pixel directly from unamanged pixel data based on the Scan0 pointer.
/// </summary> …Run Code Online (Sandbox Code Playgroud) 继续我的 F# 性能测试。有关更多背景信息,请参见此处:
f# 结构构造函数中的 NativePtr.stackalloc
现在我已经在 F# 中使用了堆栈数组。但是,出于某种原因,等效的 C# 大约快了 50 倍。我在下面包含了 ILSpy 反编译版本,看起来只有 1 行是真正不同的(在 stackAlloc 中)。
这里发生了什么?未经检查的算术真的是造成这种巨大差异的原因吗?不知道我怎么能测试这个??
https://msdn.microsoft.com/en-us/library/a569z7k8.aspx
F# 代码
#nowarn "9"
open Microsoft.FSharp.NativeInterop
open System
open System.Diagnostics
open System.Runtime.CompilerServices
[<MethodImpl(MethodImplOptions.NoInlining)>]
let stackAlloc x =
let mutable ints:nativeptr<byte> = NativePtr.stackalloc x
()
[<EntryPoint>]
let main argv =
printfn "%A" argv
let size = 8192
let reps = 10000
stackAlloc size // JIT
let clock = Stopwatch()
clock.Start()
for i = 1 to reps do
stackAlloc …Run Code Online (Sandbox Code Playgroud) 我需要将非托管内存读入托管字节数组.
为此,我有一个对非托管内存的IntPtr引用和一个长度,它表示我感兴趣的非托管内存的大小.
我使用以下代码将其读入托管字节数组.
byte[] pixelDataArray = new byte[pixelDataLength];
for (int i = 0; i < pixelDataLength; i++) {
pixelDataArray[i] = Marshal.ReadByte(pixelData, i);
}
Run Code Online (Sandbox Code Playgroud)
然而,这导致非常差的性能.使用256KB非托管内存调用此方法1000次,需要7秒以上.我认为必须有一种更有效的方法来做到这一点.
我无法使用Marshal.PtrToStructure,因为我不知道需要预先阅读的内存大小.
关于如何改进这个功能的任何想法?
我正在进行一些 F# 性能测试,并尝试在堆栈上而不是堆上创建一个数组(值与引用类型)。我正在使用 NativePtr.stackalloc 在堆栈上分配内存。在下面的第一个构造函数中出现错误。
type StackArray<'T when 'T : unmanaged> =
struct
val pointer: nativeptr<'T>
new(x) = { pointer = NativePtr.stackalloc x}
new(pointer) = { pointer = pointer}
end
// This give a System.TypeInitializationException with internal System.InvalidProgramException
let ints2 = new StackArray<int>(10)
// This works fine
let (pointer:nativeptr<int>) = NativePtr.stackalloc 10
let ints = new StackArray<int>(pointer)
Run Code Online (Sandbox Code Playgroud)
我可以简单地在函数中使用第二种方法,但是为什么我无法在构造函数内分配内存,这真的很困扰我。
我尝试了各种方法的许多不同组合来封送此调用。这是一个 DLL,它返回一个指向结构数组的指针。像 debugPort 这样的类型实际上是枚举。
/**
* \struct debugConnectParameters
* \brief Get device characterization and specify connection parameters through ST-LINK interface.
*/
typedef struct debugConnectParameters {
debugPort dbgPort; /**< Select the type of debug interface #debugPort. */
int index; /**< Select one of the debug ports connected. */
char serialNumber[33]; /**< ST-LINK serial number. */
char firmwareVersion[20]; /**< Firmware version. */
char targetVoltage[5]; /**< Operate voltage. */
int accessPortNumber; /**< Number of available access port. */
int accessPort; /**< Select access …Run Code Online (Sandbox Code Playgroud) 就这么简单,我怎么能在转换VBNET一个UnmanagedMemoryStream到字节数组?
Dim bytes() As Byte = My.Resources.AudioFile
Run Code Online (Sandbox Code Playgroud)
例外:
Value of type 'System.IO.UnmanagedMemoryStream' cannot be converted to '1-dimensional array of Byte'.
Run Code Online (Sandbox Code Playgroud) 我需要将C#字符串写入编码为Utf8的预分配非托管缓冲区.在回答之前,请阅读以下要求:
目前,我正在使用OpCodes.Cpblk将原始字符串从C#复制到使用16位字符的非托管缓冲区.这给了我与在x64架构上使用非托管memcpy大致相同的性能,我真的需要吞吐量接近它.
我正在考虑将字符串固定为char*并对其进行迭代,但实现不带跳转表的编码器既麻烦又不太理想.
当从C#创建COM对象或任何其他非托管实例时,如何在系统中分配非托管内存?