为什么访问非托管内存会导致System.AccessViolationException

本文关键字:System AccessViolationException 内存 访问 为什么 | 更新日期: 2023-09-27 18:17:57

我试图使用XGBoost的dll (libxgboost.dll)来创建一个DMatrix(这就像一个2D数组),并得到它有多少列。它可以正常运行,直到它在下面的代码中在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);

这是我的项目的repo。我使用的是Visual Studio Enterprise 2015。它在Windows 10 Pro(64位)上内置在"调试"模式(针对x64)。libxgboost.dll的X64二进制文件可以在这里找到。尽管链接的repo确实包含libxgboost.dll的副本。

为什么访问非托管内存会导致System.AccessViolationException

感谢NineBerry的回答,这是我得到的解决方案。

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);
    }
  }
}