由于 2 秒超时,并非所有本机全局变量在混合模式 .Net 应用程序中都会被破坏
在我的混合模式 C++ 应用程序中,我注意到以下奇怪的效果:
- 如果我在 Visual Studio 外部启动可执行文件,所有非托管全局变量都会被正确破坏。
- 如果我在 Visual Studio 外部启动可执行文件,然后附加调试器,所有非托管全局变量都会被正确破坏。
- II 在 Visual Studio 调试器内启动可执行文件,并非所有非托管全局变量似乎都被破坏。
我读到 .Net 有 2 秒的清理超时时间。这是为了整个非托管全局变量销毁吗?或者这是每个析构函数?
我非常确定这 2 秒超时就是原因,因为当我在 doexit 方法的开头设置断点时,调试器会在应用程序退出时停止在那里。 但是,如果我在 doexit 函数末尾附近设置断点,则永远不会命中该断点。
有没有办法在应用程序中更改 2 秒超时?问题是,如果不是所有全局变量都被破坏,我的内存泄漏检测系统将报告大量内存泄漏。
编辑:
这是一个显示问题的示例程序。
由于我想制作一个混合模式应用程序,因此我编写了一个单独的 main (本机编译)和一个单独的“add”函数(托管编译)。这是主要内容:
#include <iostream>
#include <windows.h>
extern int add(int,int);
class X
{
public:
X(char *name) : m_name(name) {std::cout << "Constructing " << m_name << std::endl;}
~X() {Sleep(1000); std::cout << "Destructing " << m_name << std::endl;}
private:
char *m_name;
};
X x1("x1");
X x2("x2");
X x3("x3");
X x4("x4");
X x5("x5");
int main()
{
std::cout << "In beginning of main" << std::endl;
int i = add(1,2);
std::cout << i << std::endl;
std::cout << "At end of main" << std::endl;
}
这是 add.cpp 文件:
int add (int one, int two)
{
int result = one;
result += two;
return result;
}
使用这些命令(使用 VS2010 和 .Net 4.0)编译和链接它们:
cl /c /EHsc /Od /Zi main.cpp
cl /c /Od /Zi /clr add.cpp
link /debug /debugtype:cv main.obj add.obj mscoree.lib nochkclr.obj /nodefaultlib:libcmt.lib
这是运行应用程序时的输出:
Constructing x1
Constructing x2
Constructing x3
Constructing x4
Constructing x5
In beginning of main
3
At end of main
Destructing x5
因此,全局变量的销毁在之后停止第一个。
如果我将睡眠时间从 1000 毫秒减少到 500 毫秒,则全局变量 x5、x4 和 x3 会被破坏,但随后它也会停止。
我将文件上传到 http://www.mediafire.com/?gil2hm2d3cw1zmz,所以如果你愿意要测试这一点,您不必再次复制/粘贴或重新输入所有内容。
编辑:稍微更改了标题,使其更加清楚,因为我们已经知道了问题的实际原因。
I my mixed-mode C++ application I notice the following strange effects:
- If I start the executable outside Visual Studio, all unmanaged global variables are correctly destructed.
- If I start the executable outside Visual Studio, then attach the debugger, all unmanaged global variables are correctly destructed.
- I I start the executable inside the Visual Studio debugger, not all unmanaged global variables seem to be destructed.
I read that .Net has a 2 second timeout for the cleanup. Is this for the whole of the unmanaged global variable destruction? Or is this per destructor?
I am quite sure that this 2 second timeout is the cause, because when I set a breakpoint in the beginning of the doexit method, the debugger stops there when the application is exit'ed.
But if I set a breakpoint near the end of the doexit function, that breakpoint is never hit.
Is there a way to change this 2 second timeout from within the application? The problem is that if not all global variables are destructed, my memory leak detection system will report lots of memory leaks.
EDIT:
This is an example program showing the problem.
Since I wanted to make a mixed-mode application, I wrote a separate main (compiled natively) and a separate 'add' function (compiled managed). This is the main:
#include <iostream>
#include <windows.h>
extern int add(int,int);
class X
{
public:
X(char *name) : m_name(name) {std::cout << "Constructing " << m_name << std::endl;}
~X() {Sleep(1000); std::cout << "Destructing " << m_name << std::endl;}
private:
char *m_name;
};
X x1("x1");
X x2("x2");
X x3("x3");
X x4("x4");
X x5("x5");
int main()
{
std::cout << "In beginning of main" << std::endl;
int i = add(1,2);
std::cout << i << std::endl;
std::cout << "At end of main" << std::endl;
}
And this is the add.cpp file:
int add (int one, int two)
{
int result = one;
result += two;
return result;
}
They are compiled and linked using these commands (using VS2010 and .Net 4.0):
cl /c /EHsc /Od /Zi main.cpp
cl /c /Od /Zi /clr add.cpp
link /debug /debugtype:cv main.obj add.obj mscoree.lib nochkclr.obj /nodefaultlib:libcmt.lib
This is the output if the application is run:
Constructing x1
Constructing x2
Constructing x3
Constructing x4
Constructing x5
In beginning of main
3
At end of main
Destructing x5
So the destruction of the global variables stops after the first one.
If I decrease the sleep from 1000 ms to 500 ms, global variables x5, x4 and x3 are destructed but then it also stops.
I uploaded the files to http://www.mediafire.com/?gil2hm2d3cw1zmz, so if you want to test this, you don't have to copy/paste or retype everything again.
EDIT: Slightly changed the title to make it more clear now that we have the actual cause of the problem.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
嗯确认问题。我需要思考/阅读更多相关内容。它开始看起来像一个错误,真的。
注意我从来没有通过调试来运行任何这些,因为我的 VS 设置不知何故失败了。感谢您进行命令行构建!
作为记录,这是我在 Win7-64、.NET 4.0、两个 CPU 核心和 1Gb RAM 上的初始运行(无需重新编译,仅是二进制文件):
在本地再次编译并没有改变任何内容。我仔细检查了一下这确实是一个混合模式工件:
检查:已确认。
Hmm confirming the problem. I'll need to think/read more about this. It is starting to look like a bug, really.
Note at no time did I run any of this with debugging, because my VS setup is somehow borked. Kudos for doing the commandline build!
For the record, here is my initial run (without recompiling, just your binary) on Win7-64, .NET 4.0, two CPU cores and 1Gb RAM):
Compiling it again locally didn't change anything. I double checked that this is indeed a mixed-mode artifact:
Check: confirmed.
@塞赫:
你自己的构建不是混合模式!这就是它正确破坏的原因。
如果您想构建混合模式应用程序,您需要添加 /clr 参数。此外,不可能将 /clr 与 /EHsc 结合起来,你必须使用 /EHa
但是我面临着像作者一样的问题......有人有解决方案吗?
@sehe:
Your own build is not mixed mode! That is why it is destructing properly.
If you want to build a mixed mode application you need to add /clr paremeter. Moreover it ist not possible to combine /clr with /EHsc, you have to use /EHa
However I am facing the same problem like the author...has anybody a solution?