【问题标题】:Why this code throws System.ExecutionEngineException为什么这段代码会抛出 System.ExecutionEngineException
【发布时间】:2010-11-05 01:29:05
【问题描述】:

背景: 我正在使用 DirectX 9.0 托管库将 3d 点数组转换为 2d 屏幕坐标。为了速度,我使用 UnsafeNativeMethods 进行所有转换。

问题: 如果使用我的自定义线剪辑功能,我的应用程序会死掉而没有抛出任何异常,我花了一段时间才发现它抛出了一个无法捕获的System.ExecutionEngineException。由于我的剪辑功能的最后两行,我已将其范围缩小到发生。

List<Vector3> verticesAfterClipping = new List<Vector3>;
public unsafe void ClipLine(Line lineToClip)
{
    this.verticesAfterClipping.Clear();

    // Clipping algorithm happens here... (this is psuedo-code of what it does)
    foreach(Vertex in lineToClip.Vertices)
    {
        bool thisIsClipped =   // Set to whether this vertex is clipped
        bool lastWasClipped =  // Set to whether last vertex was clipped

        if(thisIsClipped == false && lastWasClipped == true)
        {
            verticesAfterClipping.Add( /* intersection on clipping plane */ );
            verticesAfterClipping.Add( /* thisVertex */ );
        }
        else if (thisIsClipped == false && lastWasClipped == false)
        {
            verticesAfterClipping.Add( /* thisVertex */ );
        }
        else if (thisIsClipped == true && lastWasClipped == false)
        {
            verticesAfterClipping.Add(/* intersection on clipping plane */);
        }
    }

    // THIS IS WHERE BAD THINGS HAPPEN
    lineToClip.Vertices = new Vertex[verticesAfterClipping.Count];
    verticesAfterClipping.CopyTo(lineToClip.Vertices, 0);
}

verticesAfterClipping 列表被复制到lineToClip 顶点时,lineToClip 对象随后被传递给将这些顶点转换为二维顶点的 UnsafeNativeMethod。从我在调试模式下单步执行它时所看到的一切来看,它工作得非常好,直到它死掉。

我根本不知道哪里出了问题。任何帮助将不胜感激。

【问题讨论】:

    标签: c# exception managed-directx


    【解决方案1】:

    问题实际上可能不会发生在引发异常的行中。这可能只是之前发生的事情的征兆。

    System.ExecutionEngineException 异常会在 CLR 检测到出现严重错误时引发。这可能会在问题发生后相当长的一段时间内发生。这是因为异常通常是内部数据结构损坏的结果——CLR 发现某些东西进入了没有意义的状态。它会抛出一个无法捕获的异常,因为它不安全。

    因此,您可能在系统的某些完全不相关的部分中有一些代码会破坏某些东西,但这只有在这段特定的代码运行时才会变得明显。您显示的代码可能很好。 (也可能不是......我没有看到任何明显的错误,但是我不太了解 DX 9 托管库。例如,我看不出该方法的哪个功能需要 unsafe 关键字。 )

    不幸的是,这意味着您需要开始将网络撒得更宽一些。几乎所有使用不安全代码或 COM 互操作的东西都可能受到怀疑。遗憾的是,这将是一个漫长而乏味的过程。您可能会采用的一种方法是尝试逐渐简化程序:可以说明问题的最小代码是什么? (例如,如果您将此处显示的代码放入一个应用程序中,该应用程序只包含对该方法的最简单调用,它仍然会失败吗?)

    【讨论】:

    • 当您说异常不会发生在这两行上时,您是对的,但它确实是这两行的结果。我替换了这些行并使用另一个临时缓冲区来复制剪切的顶点,现在一切正常。我想当该行被传递给不安全的本机 directx 方法时,在幕后发生了某种内存访问冲突。
    • 不要假设没有 ExecutionEngineException 意味着问题已经消失。可能仅仅是 CLR 不再检测它。通过替换这些行,您现在可能处于数据损坏的情况,但您不再遇到异常。 (CLR 不会也不能保证在出现此类问题时抛出 ExecutionEngineException。它只会在碰巧注意到时抛出它。)所以我会担心 - 我肯定会试图深入了解 崩溃是如何发生的,就目前而言,没有理由相信你真的修复了它。
    【解决方案2】:

    我对不同的库有同样的问题。就我而言,这一切早在很久以前就开始了,因为我必须在 64 位环境中运行 32 位 .net 应用程序。嗯,这给我带来了很多麻烦,架构之间的兼容性,或者你的 .NET 框架的 CLR 之间的兼容性也可能是你的问题。

    PS:现在我知道什么我的问题是,但不知道在哪里

    【讨论】:

    • 这对我来说是这个错误的原因。我在 AnyCPU 中有我的项目,它需要是 x64。我一读到您的评论,就提示我尝试一下,这立即奏效了。
    【解决方案3】:

    我有两个类处理我的数据库中的特定表

    StorageManager - 具有处理与数据库直接交互的方法的类

    Controller - 具有处理 api 调用的方法的类

    当表中即将创建新条目时,我会检查子表中可能已经存在的某些值。

    我编写了这些方法来检查错误类中的预先存在/重复,这最终导致为我抛出 executionengineexception。

    移动方法以便它们与正确的数据库上下文一起生活似乎对我来说解决了这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-18
      相关资源
      最近更新 更多