为啥访问非托管内存会导致 System.AccessViolationException? [复制]

Posted

技术标签:

【中文标题】为啥访问非托管内存会导致 System.AccessViolationException? [复制]【英文标题】:Why does accessing unmanaged memory cause a System.AccessViolationException? [duplicate]为什么访问非托管内存会导致 System.AccessViolationException? [复制] 【发布时间】:2016-11-14 01:47:33 【问题描述】:

我正在尝试使用XGBoost's dll (libxgboost.dll) 创建一个 DMatrix(类似于二维数组)并获取它有多少列。它运行良好,直到它在下面的代码中的int cols = ... 行抛出一个System.AccessViolationException

using System;
using System.Runtime.InteropServices;

namespace basicXgboost

  class Program
  
    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
    public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, IntPtr outputPtr);

    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
    public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, IntPtr dmatrixColumnsPtr);

    static void Main(string[] args)
    
      IntPtr dmatrixPtr = Marshal.AllocHGlobal(1000000);
      IntPtr dmatrixColumnsPtr = Marshal.AllocHGlobal(10);

      int result = XGDMatrixCreateFromFile("../../libs/test.txt", 0, dmatrixPtr);
      int cols = XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr);

      Marshal.FreeHGlobal(dmatrixPtr);
      Marshal.FreeHGlobal(dmatrixColumnsPtr);
    
  

为什么访问用XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr) 分配的非托管内存会导致System.AccessViolationException

一种可能性可能是我对这些功能错误地使用了 pinvoke。以下是我使用的每个 dll 函数的定义:

XGDMatrixCreateFromFile()

/*!
 * \brief load a data matrix
 * \param fname the name of the file
 * \param silent whether print messages during loading
 * \param out a loaded data matrix
 * \return 0 when success, -1 when failure happens
 */
XGB_DLL int XGDMatrixCreateFromFile(const char *fname,
                                    int silent,
                                    DMatrixHandle *out);

XGDMatrixNumCol()

/*!
 * \brief get number of columns
 * \param handle the handle to the DMatrix
 * \param out The output of number of columns
 * \return 0 when success, -1 when failure happens
 */
XGB_DLL int XGDMatrixNumCol(DMatrixHandle handle,
                            bst_ulong *out);

Here 是我项目的仓库。我正在使用 Visual Studio Enterprise 2015 。它在 Windows 10 Pro(64 位)上以“调试”模式(针对 x64)构建。可以在 here 找到 libxgboost.dll 的 x64 二进制文件。尽管链接的 repo 确实包含 libxgboost.dll 的副本。

【问题讨论】:

Marshal.AllocHGlobal(10); 分配 10 个字节还是 10 个整数?你有多确定只有 10 列? 我认为如果我正在阅读docs 权利,它会分配10 个字节。 10 只是我用来在内存中存储整数的任意字节数(它可以引用的不仅仅是 10 列)。 如果 XGDMatrixNumCol 填充了 bst_ulong 参数,那么您需要知道 bst_ulong 有多大 - 它是多于还是少于 10 个字节? 好的,有道理,谢谢 NineBerry。我以后会这样做 :) 我又这样做了,因为我收到了很多关于如何重新格式化问题以便人们更容易查看的良好反馈。 Jerry Jeremiah 我认为根据它的定义它不到 10 个字节here 【参考方案1】:

感谢NineBerry's answer,这是我得到的解决方案。

using System;
using System.Runtime.InteropServices;

namespace basicXgboost

  class Program
  
    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
    public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, out IntPtr outputPtr);

    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
    public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, out ulong dmatrixColumnsPtr);

    static void Main(string[] args)
    
      IntPtr dmatrixPtr;
      ulong dmatrixColumns;

      int result = XGDMatrixCreateFromFile("../../libs/test.txt", 0, out dmatrixPtr);
      int cols = XGDMatrixNumCol(dmatrixPtr, out dmatrixColumns);
    
  

【讨论】:

检查返回值。他们在那里是有原因的。 XGDMatrixCreateFromFile 可能会失败。

以上是关于为啥访问非托管内存会导致 System.AccessViolationException? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

当 CPU 尝试读取由 GPU 初始化的托管内存时,为啥数据会从主机迁移到设备?

记一次 .NET 某工控视觉软件 非托管泄漏分析

为啥将托管 .NET 客户端设置为使用 STA 线程会导致本机 COM 服务器中出现异常问题?

托管和非托管的c++是啥意思,有啥区别?

为啥会出错啊!???????

函数调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。