C++ 使用CreateProcess时会出现奇怪的减速

C++ 使用CreateProcess时会出现奇怪的减速,c++,winapi,visual-c++,createprocess,C++,Winapi,Visual C++,Createprocess,让我从一些示例代码开始。我已经为此做了一个最低限度的测试用例。要复制,需要两个部件: 第一个可执行文件,一个使用CreateProcess的小应用程序。我们称之为调试器 尤其是RtlpNtMakeTemporaryKey似乎出现了很多。不幸的是,我不知道这意味着什么,谷歌似乎也没有帮助…在调试堆中有所不同。阅读 及 当进程初始化的系统ntdll检查存在调试器时,如果检查是环境变量_NO_DEBUG_HEAP存在并设置为非零。如果否-在PEB中设置NtGlobalFlag以调试堆使用FLG_hea

让我从一些示例代码开始。我已经为此做了一个最低限度的测试用例。要复制,需要两个部件:

第一个可执行文件,一个使用CreateProcess的小应用程序。我们称之为调试器


尤其是RtlpNtMakeTemporaryKey似乎出现了很多。不幸的是,我不知道这意味着什么,谷歌似乎也没有帮助…

在调试堆中有所不同。阅读

当进程初始化的系统ntdll检查存在调试器时,如果检查是环境变量_NO_DEBUG_HEAP存在并设置为非零。如果否-在PEB中设置NtGlobalFlag以调试堆使用FLG_heap_ENABLE_TAIL_CHECK、FLG_heap_ENABLE_FREE_CHECK、FLG_heap_VALIDATE_参数所有这些检查,并在块的末尾使用特殊模式baadf00d和ABABABABABABABAB填充所有分配的块,使所有堆alloc/FREE慢速比较不出现这种情况

从另一方面来说,程序大部分时间用于从堆中分配/释放内存

该概要文件还显示了这个-RtlAllocateHeap,memset-sure,当分配的块中填充了魔术模式时,RtlpNtMakeTemporaryKey-这个函数由一条指令组成-jmp ZwDeleteKey-所以您实际上不在这个函数内部,而是在它附近,在另一个与heap相关的函数内部

正如Simon Mourier所指出的,为什么在没有调试器的情况下,案例2和案例3的运行速度与案例1一样快,而只有案例4的运行速度更慢

这样,在启动C++应用程序时,性能会有所提高 Visual Studio调试器,在Visual Studio 2015中,我们禁用了 系统的调试堆

这是通过在已调试的进程环境中设置_NO_DEBUG_HEAP=1来完成的。所以,比较文章是旧的-现在这是默认情况下

我们可以通过应用程序中的下一个代码来检查这一点:

WCHAR _no_debug_heap[32];
if (GetEnvironmentVariable(L"_NO_DEBUG_HEAP", _no_debug_heap, _countof(_no_debug_heap)))
{
    DbgPrint("_NO_DEBUG_HEAP=%S\n", _no_debug_heap);
}
else
{
    DbgPrint("error=%u\n", GetLastError());
}
所以当我们在debugger下启动应用程序时-没有调试堆,因为VS debugger add _no_debug_heap=1。在调试器下启动调试器时,从调试器启动应用程序-从函数

LPE环境

指向新进程的环境块的指针。如果这 参数为NULL,则新进程使用调用的环境 过程

因为您在此处传递0-所以应用程序使用与调试器相同的环境-继承_NO_DEBUG_HEAP=1


但是在案例4中,您没有自行设置_NO_DEBUG_HEAP=1。因此,使用了调试堆,运行速度较慢。

调试堆中的情况不同。阅读

当进程初始化的系统ntdll检查存在调试器时,如果检查是环境变量_NO_DEBUG_HEAP存在并设置为非零。如果否-在PEB中设置NtGlobalFlag以调试堆使用FLG_heap_ENABLE_TAIL_CHECK、FLG_heap_ENABLE_FREE_CHECK、FLG_heap_VALIDATE_参数所有这些检查,并在块的末尾使用特殊模式baadf00d和ABABABABABABABAB填充所有分配的块,使所有堆alloc/FREE慢速比较不出现这种情况

从另一方面来说,程序大部分时间用于从堆中分配/释放内存

该概要文件还显示了这个-RtlAllocateHeap,memset-sure,当分配的块中填充了魔术模式时,RtlpNtMakeTemporaryKey-这个函数由一条指令组成-jmp ZwDeleteKey-所以您实际上不在这个函数内部,而是在它附近,在另一个与heap相关的函数内部

正如Simon Mourier所指出的,为什么在没有调试器的情况下,案例2和案例3的运行速度与案例1一样快,而只有案例4的运行速度更慢

这样,在启动C++应用程序时,性能会有所提高 Visual Studio调试器,在Visual Studio 2015中,我们禁用了 系统的调试堆

这是通过在已调试的进程环境中设置_NO_DEBUG_HEAP=1来完成的。所以,比较文章是旧的-现在这是默认情况下

我们可以通过应用程序中的下一个代码来检查这一点:

WCHAR _no_debug_heap[32];
if (GetEnvironmentVariable(L"_NO_DEBUG_HEAP", _no_debug_heap, _countof(_no_debug_heap)))
{
    DbgPrint("_NO_DEBUG_HEAP=%S\n", _no_debug_heap);
}
else
{
    DbgPrint("error=%u\n", GetLastError());
}
所以当我们在debugger下启动应用程序时-没有调试堆,因为VS debugger add _no_debug_heap=1。在调试器下启动调试器时,从调试器启动应用程序-从函数

LPE环境

指向新进程的环境块的指针。如果这 参数为NULL,则新进程使用调用的环境 过程

因为您在此处传递0-所以应用程序使用与调试器相同的环境-继承_NO_DEBUG_HEAP=1


但是在案例4中,您没有自行设置_NO_DEBUG_HEAP=1。结果是使用了调试堆,运行速度变慢。

没有附加任何内容意味着什么?每行n秒意味着什么?TestProject.exe是应用程序吗?@WernerHenze“未附加任何内容”表示仅从Windows资源管理器启动exe。每行N秒意味着需要N秒来生成i的单个迭代。是的,TestProject.exe就是应用程序。我将更新问题,感谢您的反馈。调试器在任何情况下都会看到任何调试事件吗?哪个和多少?“这有区别吗?”沃内尔亨兹问得好,这也是我最初的猜测。答案是:不是在测试执行期间,只是在加载dll之前和之后,启动/退出进程等。换句话说:否

生成相关事件。零。我注意到的一件事是,向量副本构造函数在世界上发挥了巨大的作用。如果没有它,时间安排几乎是你所期望的。有了它,一些奇怪的事情正在发生……没有任何附加的东西意味着什么?每行n秒意味着什么?TestProject.exe是应用程序吗?@WernerHenze“未附加任何内容”表示仅从Windows资源管理器启动exe。每行N秒意味着需要N秒来生成i的单个迭代。是的,TestProject.exe就是应用程序。我将更新问题,感谢您的反馈。调试器在任何情况下都会看到任何调试事件吗?哪个和多少?“这有区别吗?”沃内尔亨兹问得好,这也是我最初的猜测。答案是:不是在测试执行期间,只是在加载dll之前和之后,启动/退出进程等。换句话说,没有生成相关事件。零。我注意到的一件事是,向量副本构造函数在世界上发挥了巨大的作用。如果没有它,时间安排几乎是你所期望的。有了它,一些奇怪的事情正在发生……每个人都知道在调试器下运行会因为各种原因而变慢,但是——或者可能我遗漏了什么——这并不能解释为什么在VS调试器下运行4比在VS调试器下运行3慢。@SimonMourier——同意你的问题。这对我来说只是不清楚。这可能是在project app和debugger中设置的,这解释了为什么在没有调试器的情况下从VS debugger运行代码时比较不慢,但这是非常不寻常的,并且不是默认情况。这里需要更多的信息和研究,但我确信时间的来源不同-在4种情况下调试堆。我是问打印在所有3开始case@SimonMourier我自己不能在这里做测试/检查。但我确信不同的堆内设置是不同的源。所以需要在开始时检查。然后,如果我的假设正确,检查app中的_NO _DEBUG _HEAP-此变量是否存在,如果存在-它的值我还尝试了启用Windows调试堆分配器纯本机工具/选项/调试设置。选中时,3和4运行相同的操作。因此,总的来说,除非选中此设置,否则它似乎意味着在VS debugger set _NO_DEBUG_HEAP=1下运行。我想这就是他们在这里说的:。。。当使用VS调试器启动C++应用程序时…我们禁用了操作系统的调试堆…,而只调用CreateProcess w debug\u PROCESS即可启用它。@SimonMourier-我只是在vs2019调试器下启动代码,并设置了view _NO\u debug\u heap=1变量。这是我的全部解释。即使我们没有在“项目设置”中手动设置,这也是默认设置。因为2和1同时运行。如果不直接设置环境,则环境将被继承。结果3也作为1运行,应用程序从调试器继承_NO_DEBUG_HEAP=1。但是在案例4中-no _no _DEBUG _HEAP=1由于各种原因,每个人都知道在调试器下运行会比较慢,但是-或者可能我遗漏了什么-这并不能解释为什么在VS调试器下运行4比在VS调试器下运行3慢。@SimonMourier-同意你的问题。这对我来说只是不清楚。这可能是在project app和debugger中设置的,这解释了为什么在没有调试器的情况下从VS debugger运行代码时比较不慢,但这是非常不寻常的,并且不是默认情况。这里需要更多的信息和研究,但我确信时间的来源不同-在4种情况下调试堆。我是问打印在所有3开始case@SimonMourier我自己不能在这里做测试/检查。但我确信不同的堆内设置是不同的源。所以需要在开始时检查。然后,如果我的假设正确,检查app中的_NO _DEBUG _HEAP-此变量是否存在,如果存在-它的值我还尝试了启用Windows调试堆分配器纯本机工具/选项/调试设置。选中时,3和4运行相同的操作。因此,总的来说,除非选中此设置,否则它似乎意味着在VS debugger set _NO_DEBUG_HEAP=1下运行。我想这就是他们在这里说的:。。。当使用VS调试器启动C++应用程序时…我们禁用了操作系统的调试堆…,而只调用CreateProcess w debug\u PROCESS即可启用它。@SimonMourier-我只是在vs2019调试器下启动代码,并设置了view _NO\u debug\u heap=1变量。这是我的全部解释。即使我们没有在“项目设置”中手动设置,这也是默认设置。因为2和1同时运行。如果不直接设置环境,则环境将被继承。结果3也作为1运行,应用程序从调试器继承_NO_DEBUG_HEAP=1。但是在案例4中-no\u no\u DEBUG\u HEAP=1
352       - inside memset (address: 0x7ffa727349d5)
284       - inside RtlpNtMakeTemporaryKey (address: 0x7ffa727848b2)
283       - inside RtlAllocateHeap (address: 0x7ffa726bbaba)
261       - inside memset (address: 0x7ffa727356af)
180       - inside RtlFreeHeap (address: 0x7ffa726bfc10)
167       - inside RtlpNtMakeTemporaryKey (address: 0x7ffa72785408)
161       - inside RtlGetCurrentServiceSessionId (address: 0x7ffa726c080f)
WCHAR _no_debug_heap[32];
if (GetEnvironmentVariable(L"_NO_DEBUG_HEAP", _no_debug_heap, _countof(_no_debug_heap)))
{
    DbgPrint("_NO_DEBUG_HEAP=%S\n", _no_debug_heap);
}
else
{
    DbgPrint("error=%u\n", GetLastError());
}