发布模式VS MS Visual Studio Windows中的DEbug模式

我正在使用MSVS 9(VS 2008)。 我的应用程序以及共享库(dll)(我用于链接我的应用程序)也是c ++环境。 现在观察下面的情况:

  • 当共享库/ dll以Debug模式构建并且我的应用程序也以Debug模式构建时结果:应用程序成功执行

  • 当共享库/ dll构建在发布模式下时,我的应用程序也构建在发布模式下结果:应用程序成功执行

  • 当共享库/ dll构建在发布模式下时,我的应用程序也是以调试模式构建的。结果:应用程序崩溃时没有从调用堆栈加载任何符号。

    调用堆栈:

    ntdll.dll中!76e94684()
    [以下帧可能不正确和/或丢失,没有为ntdll.dll加载符号]

    ntdll.dll中!76e7d55f()
    ntdll.dll中!76e5fa18()
    ntdll.dll中!76e2b3c8()

  • 当我尝试在我的应用程序中使用以下SetName()和GetName()定义时,会看到此问题。

        using namespace std;
        void main()
        { 
            Schema * schemaExp = new Schema();
            schemaExp -> SetName("ExpSchema");
            string srctable;
            srctable=schemaExp->GetName();
            cout <<"nConnection EXPORT using the target table:" << srctable.c_str()  << endl;
            delete schemaExp;
        }
    

    模式类定义:

        using namespace std;
        class Schema
        {
           public:
           TELAPI_EXPORT void   SetName(char *name); 
           TELAPI_EXPORT string     GetName(); 
          protected: 
           string tableName; 
        };
        void Schema::SetName(char *name)
        { 
           string str(name);
           tableName = str; 
        }
        string Schema::GetName()
        {
          return tableName;
        }
    

    注意:上面的一个只是我应用程序的一部分,我的应用程序只在#3中崩溃,并在上面的#1和#2情况下正常工作

    请帮我解决这个问题。 任何形式的帮助,不胜感激。

    提前致谢。


    当共享库/ dll构建在发布模式下时,我的应用程序也是以调试模式构建的。结果:应用程序崩溃时没有从调用堆栈加载任何符号。

    这是因为这不是受支持的配置。 默认情况下,调试和发布目标链接到不同版本的CRT,(除其他外)使用不同的策略来分配内存,并且彼此不兼容。

    这只是更一般的规则的扩展,你不应该混合链接到不同版本CRT的库。 所有的项目都需要匹配。 正如你已经看到的,当他们这样做时,一切正常。

    对此有一些解决方法,但他们需要做很多工作才能获得正确的结果。 从本质上讲,你要确保所有的内存分配都在单个DLL中隔离,这样就没有任何东西跨越模块边界。 您需要从DLL中导出特定的函数以分配和释放内存,以确保分配内存的堆管理器与销毁内存的堆管理器相同。 当你使用newdelete操作符时,你不能依赖这种情况。 坦率地说,在这种情况下,我不明白这些努力如何为你带来什么有用的东西。

    请注意,这与是否启用优化无关(默认情况下它们是Release版本,不在Debug版本中)。 该设置与所链接CRT的版本正交。“调试”和“发布”目标意味着多个选项。 您可以打开一个项目的优化并关闭另一个项目,只要确保它们都链接到相同版本的CRT,就可以工作。 但是,我再也看不到这一点......如果你想为其中一个优化启用,你为什么要让它们为另一个优化呢?

    相关:混合调试和发布库/二进制文件 - 不好的做法?


    这不应该是一个崩溃,但是,通常你会在Windows内存管理器中得到一个调试中断来警告你,你的程序正在销毁这个堆。 Windows中调试堆的功能,可在Vista和更高版本上使用。 在输出窗口中查找消息。

    启用符号服务器以使堆栈跟踪变得可读和准确也很重要。 使用工具+选项,调试,符号执行此操作,并勾选预定义的msdl.microsoft.com服务器名称前面的复选框。 为符号存储选择一个好的暂存目录。 当你再次启动你的程序时,它会在开始运行之前运行一段时间,下载符号文件。 这只发生一次。 你现在应该得到一个高度可读的堆栈跟踪,现在也可以回到你的main()方法。

    你一般发现,跨模块边界暴露C ++类是棘手的业务。 不止一件事可能会出错,这里的一种失败模式是模式类对象在DLL边界两侧的大小不一样。 这是因为Debug版本设置,_HAS_ITERATOR_DEBUGGING#定义很重要。 它在Debug版本中默认打开,在Release版本中关闭。 好的调试功能,但他们可以实现它的唯一方法是向标准C ++库类添加字段。 这使得Debug版本中的std :: string更大。 这使得你的Scheme类变得更大。 您现在正在避开这个问题,失败模式是DLL的调试版本与EXE的发布版本。 然后,Scheme类构造函数在初始化字符串时会破坏堆,因为对象的分配不够大。

    另一种失败模式是,您的流程中有两个版本的CRT,应用中的调试版本和DLL中的发布版本。 他们不会使用相同的堆来分配。 当你分配一个而另一个释放时,会出错。 由你的GetName()方法返回的字符串会遇到这个问题,它是在DLL中的GetName()方法中创建的,并且会在EXE中的方法调用后被销毁。 由错误的分配器。 直到您再次对堆执行某些操作(例如删除Scheme对象)之后,才会检测到堆所造成的损坏。 如果您没有使用/ MD构建您的代码,您还将调用此失败模式。 VS2012顺便解决了这个问题,现在所有的分配都是由默认的进程堆进行的。

    使用一致的构建设置对于在模块边界中生存至关重要。 设置你的VS解决方案,以便始终如一地为DLL使用正确的版本不是问题,只要确保DLL项目与EXE项目在同一解决方案中即可。

    但是请注意,将来你可能会遇到麻烦,一个DLL拥有一个自己的生活诀窍,并且可能有一天会被另一个版本的编译器构建的应用程序使用。 然后Kaboom。 设计你的DLL接口是绝对不可能的,但你必须放弃暴露C ++对象。 C风格的界面是后备,COM工作方式将其提升到对象模型也是一种好方法。 当然,这非常严格,如果你不能保证EXE和DLL总是在同一时间被构建和部署,那么只考虑这一点。

    链接地址: http://www.djcxy.com/p/95391.html

    上一篇: Release mode Vs DEbug mode in MS Visual Studio Windows

    下一篇: Debugging ASP.NET web service, C++/CLI DLL, and native DLL in Visual Studio 2008