从Finalize中删除非托管对象会引发AccessViolationException

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从Finalize中删除非托管对象会引发AccessViolationException相关的知识,希望对你有一定的参考价值。

我正在使用C ++ / CLI为非托管C ++项目编写一个包装器库。目标是将此库公开给C#应用程序。这是我到目前为止所拥有的。

#pragma once

#include "Settings.h"
#include "Settings/SettingsPrivate.h"

public ref class Settings
{
public:
    Settings();
    virtual ~Settings();

protected:
    !Settings();

public:
    unsigned char GetModel(int iNumber);


private:
    CSettings* m_pSettings;
};

#include "stdafx.h"
#include "Managed/Settings.h"

Settings::Settings()
{
    // Pointer to unmanaged object
    m_pSettings = new CSettings();
}

Settings::~Settings()
{
    this->!Settings();
}

Settings::!Settings()
{
    if (m_pSettings)
    {
        delete m_pSettings;
        m_pSettings = NULL;         
    }
}

unsigned char Settings::GetModel(int iNumber)
{
    return m_pSettingss->GetModel(iNumber);
}

代码在我编写的测试应用程序中执行正常。函数调用成功。问题是,当GC完成此对象时,它会抛出异常。

Wrapper.dll中发生了未处理的“System.AccessViolationException”类型异常

附加信息:尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

我看不出为什么抛出这个异常有任何明显的原因。我尝试通过从C#应用程序调用Dispose来显式处理该对象。它仍然会抛出相同的异常。

这是测试应用程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WrapperTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Settings settings = new Settings();
            byte b = settings.GetModel(0);

            settings.Dispose();

            return;
        }
    }
}

有人会指出我做错了什么?

答案

这是一个项目配置错误。代码实际上在Release模式下正常运行。

在调试模式下,当我应该静态链接调试库时,我在一些版本DLL中链接。为什么这会导致内存损坏我还没有调查,但它已经解决了这个问题。

否则上面发布的代码是正确的。

另一答案

您应该启用更详细的堆调试功能。我测试了你的代码,但对我来说并没有失败。我不得不使用malloc / free而不是new / delete,因为你没有定义CSettings,但效果应该是相同的。

我添加了这个以确保我有足够的堆流失来触发失败,如果他们是任何腐败;

unsigned char Settings::GetModel(int iNumber)
{   
    for(int i=0; i < iNumber; i++)
        free(malloc(1024));
    return iNumber;
}

对我来说,你的代码没有失败。您应该查看一些编译设置,是否链接到CSettings的外部库?如果是这样,你需要确保CRT是相同版本等。另外你知道你必须使用DLL运行时之一不是/ MT或/ MTd。

以上是关于从Finalize中删除非托管对象会引发AccessViolationException的主要内容,如果未能解决你的问题,请参考以下文章

Dispose() 用于清理托管资源?

从 .NET 代码中销毁非托管对象

使用 P/Invoke 在托管和非托管回调链上引发异常

"每日一道面试题".net托管堆是否会存在内存泄漏的情况

.NET 外部非托管库函数引发无法捕获的异常

Windows 运行时中的内存管理