从C#通过PInvoke调用_msize()函数

3

我正在编写一个C#库,调用应用程序将传递大量连续的、非托管的内存。这个调用应用程序可以来自.Net或Visual C++(如果来自C++,它将通过一个中间的C++/CLI库调用我的库)。验证是否有足够的内存会很有用,所以我决定调用_msize()函数。不幸的是,_msize总是给我错误的大小。

我回去修改了样例应用程序的分配例程,然后立即调用_msize。以下是我的代码片段:

public unsafe class MyMemory
{
    /// <returns></returns>
    [DllImport("msvcrt.dll", SetLastError = true)]
    public static extern int _msize(IntPtr handle);

    public static IntPtr MyAlloc(int size)
    {
        IntPtr retVal = Marshal.AllocHGlobal(size);

        ...

        int memSize = MyMemory._msize(retVal);
        if (memSize < size)
        {
        ...
        }
        return retVal;
    }

当我传入大小为199229440时,返回的memSize为199178885。我看到了类似的结果,对于不同的数字也是如此。它的偏差小于0.01%,如果超过了我完全可以理解,但事实是它低于要求的值,这意味着_msize认为分配的内存少于要求的。有人知道为什么吗?还有,任何关于我应该做些什么的建议也将不胜感激。

_msize 返回一个 size_t,它是无符号的(通常通过 IntPtr 进行映射)。并不是说这是你的问题,但这是需要注意的。 - Ed S.
Windows程序中有多个堆。AllocHGlobal从不同的堆中分配内存。_msize只能为malloc()分配的内存提供准确的信息。您可以通过调用LocalSize(而不是名称所示的GlobalSize)来获得所需内容。忘记分配的大小相当奇怪,请务必不要假设IntPtr来自正确的堆。 - Hans Passant
1个回答

2
请使用P/Invoke函数调用LocalSize函数。 _msize 用于确定使用malloc(及其相关函数)分配的块的大小。 AllocHGlobalGlobalAllocLocalAlloc的包装器(取决于您相信什么参考资料;但我认为两者是等效的),您需要LocalSize函数来确定实际返回的块的大小。据我所知,Marshal不包含LocalSize的包装器,但您可以使用P/Invoke调用它。
因此,看起来_msize能够为您提供任何有用的返回值只是纯属巧合。也许malloc总是使用GlobalAlloc(或LocalAlloc),无论何时请求大块内存都会为管理而请求一些额外的空间;在这种情况下,_msize将尝试进行补偿。

LocalSize 给出了正确的答案。感谢解释。我仍然很好奇为什么 _msize 给出了接近的结果,我能够得到许多不同大小的类似结果... - Beast

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接