【问题标题】:memory leak when calling unmanaged code from managed code in Windows 7从 Windows 7 中的托管代码调用非托管代码时发生内存泄漏
【发布时间】:2010-12-03 02:13:22
【问题描述】:

当我从我的 C# 代码调用非托管 C++ 代码时,我似乎有某种内存泄漏。
C++ 使用 ifstream.read 从文件中读取数据,并将其写入 Vector。

这仅在升级到 Windows 7 后发生,在 Vista 上不会发生,但如果我使用在 Vista 上编译的本机 dll 版本,它不会改变任何东西!
如果我直接运行相同的 C++ 代码,没有托管互操作,就不会发生内存泄漏!
如果我运行托管进程,但在 vshost 进程中,没有内存泄漏!

这是调用签名:

        [DllImport(DllPath, CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.I1)]
    public static extern bool MyMethod(
        int x, 
        string  y, 
        string  z, 
        bool    v, 
        bool    w);

还有原生的:

MyDll_Export bool APIENTRY MyMethod(
int x,
const wchar_t*  y, 
const wchar_t*  z,
bool v,
bool w)

当我从 C++ 中调用它时,我会这样称呼它:

MyMethod(1, L"My String 1", L"My String 2", true, true)

当我查看托管和非托管内存的性能计数器时,我发现所有内存都来自非托管代码。
考虑到编组非常简单,我不明白为什么直接调用 C++ 或通过 C# 调用有区别。
我也不知道为什么这只会发生在 Windows 7 上(两个 Windows 安装都有 .net 3.5 SP1)。

有人知道这是什么原因吗?

另外,如果有人知道适用于 Window 7 的本机内存分析工具,我会很高兴知道(现在我刚刚打印了所有显式内存分配的控制台,没有任何区别)。

【问题讨论】:

  • LeakDiag [mcfunley.com/277/… 或 AutomatedQA 的 AQTime 可以进行非托管泄漏分析。
  • 您使用哪个性能计数器来测量内存消耗?
  • 您已标记问题“vshost.exe”。测量内存消耗时,应用程序是否在 Visual Studio 下运行?
  • @Lou:在 Windows 7 上都不起作用。@Peter:我检查了“进程 - 私有字节”的本机分配和 CLR 内存的托管。我标记了 vshost.exe 是因为“如果我运行托管进程,但在 vshost 进程中,没有内存泄漏”,则常规进程的内存措施已关闭。

标签: c# c++ windows-7 memory-leaks vshost.exe


【解决方案1】:

我确定问题与将 C# 数据类型编组到其 C++ 对应部分有关。由于您将返回值 bool 编组为带符号的 1 字节值,也许您应该对函数参数执行相同的操作? C# bool 类型是 4 个字节,可能你在那儿泄漏了?

此外,为字符串指定非托管类型可能会有所帮助。

[DllImport(DllPath, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool MyMethod(
        int x,
        [MarshalAs(UnmanagedType.LPWStr)]
        [In] string y,
        [MarshalAs(UnmanagedType.LPWStr)]
        [In] string z,
        [MarshalAs(UnmanagedType.I1)]
        bool v,
        [MarshalAs(UnmanagedType.I1)]
        bool w);

评论者的解释:

For the C++ bool type:

一般来说,零或空指针 值被转换为假,任何其他 值被转换为真。

...

1998 年 C++ 标准库定义 向量的特殊化 布尔模板。的描述 该类表明 实施应打包 元素,以便每个布尔仅使用 一点记忆。

所以,几乎无论你使用什么值,你都会得到一个值为 true 或 false 的 c++ 布尔值。

【讨论】:

  • 如果 bool 的大小不匹配,则不会是内存泄漏,但更可能是访问冲突或某种堆栈损坏。
  • 不错的文件 scott,c# marshals bools 为 4bytes。 v 和 w 缺少 marshalas 属性。 blogs.msdn.com/oldnewthing/archive/2009/08/13/9867383.aspx
  • 谢谢,读得很好,但没有帮助。正如我在另一条评论中提到的,我只调用了一次这个方法,所以即使那里有泄漏,也不会引起注意。
  • @Meidan Alon,你调用这个方法时泄漏了多少内存?
  • 我在 2 个时间点进行了测量。如果没有泄漏,私有字节为 37k 和 66k;泄漏为 90k 和 1.7G。所以它的增长速度非常快!
【解决方案2】:

不幸的是,一旦涉及到字符串,编组就不简单了。

我们需要更多数据来帮助您找出这个问题。能否提供以下内容

  • 本机方法签名
  • 本地代码中字符串的内存是如何管理的?
  • 也许是您使用 API 的 C++ 示例?

编辑

试试下面的签名。这告诉 CLR 不要在两个方向上编组内存,而只是将数据传入。

    [DllImport(DllPath, CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.I1)]
    public static extern bool MyMethod(
            int x, 
            [In] string  y, 
            [In] string  z, 
            bool    v, 
            bool    w);

【讨论】:

  • [In] 没有帮助,为什么它会在 Vista 和 Windows 7 之间发生变化?另外,我没有提到我只调用了一次这个方法。
【解决方案3】:

我发现使用CLR Profiler 有助于发现我的内存泄漏。

【讨论】:

    【解决方案4】:

    你确定有内存泄漏吗?

    您确定内存泄漏的依据是什么。您说您可以从性能计数器中看到它,但您实际观察到的是什么?您看到的是一条持续上升的曲线,还是一条稳定在高位的曲线?高内存消耗经常被混淆为内存泄漏。

    顺便说一句。你也可以发布你的 C++ 函数定义吗?

    【讨论】:

    • 我看到一个持续上升的曲线。我已经发布了 C++ 函数定义,如果你指的是主体,那么它只是使用 ifstream.read 从文件中读取数据
    猜你喜欢
    • 1970-01-01
    • 2020-06-03
    • 2023-03-05
    • 2013-08-24
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 2015-02-24
    • 1970-01-01
    相关资源
    最近更新 更多