调用 QTcpSocket::setSocketDescriptor() 时崩溃
Crashing when calling QTcpSocket::setSocketDescriptor()
我的项目使用 QTcpSocket
和函数 setSocketDescriptor()
。代码很正常
QTcpSocket *socket = new QTcpSocket();
socket->setSocketDescriptor(this->m_socketDescriptor);
此编码大部分时间都运行良好,直到我 运行 在 Windows Server 2016 上进行性能测试时,崩溃发生了。我使用故障转储进行调试,这是日志
0000004f`ad1ff4e0 : ucrtbase!abort+0x4e
00000000`6ed19790 : Qt5Core!qt_logging_to_console+0x15a
000001b7`79015508 : Qt5Core!QMessageLogger::fatal+0x6d
0000004f`ad1ff0f0 : Qt5Core!QEventDispatcherWin32::installMessageHook+0xc0
00000000`00000000 : Qt5Core!QEventDispatcherWin32::createInternalHwnd+0xf3
000001b7`785b0000 : Qt5Core!QEventDispatcherWin32::registerSocketNotifier+0x13e
000001b7`7ad57580 : Qt5Core!QSocketNotifier::QSocketNotifier+0xf9
00000000`00000001 : Qt5Network!QLocalSocket::socketDescriptor+0x4cf7
00000000`00000000 : Qt5Network!QAbstractSocket::setSocketDescriptor+0x256
在 stderr 日志中,我看到了那些日志
CreateWindow() for QEventDispatcherWin32 internal window failed (Not enough storage is available to process this command.)
Qt: INTERNAL ERROR: failed to install GetMessage hook: 8, Not enough storage is available to process this command.
这是函数,代码在 Qt 代码库中停止
void QEventDispatcherWin32::installMessageHook()
{
Q_D(QEventDispatcherWin32);
if (d->getMessageHook)
return;
// setup GetMessage hook needed to drive our posted events
d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
if (Q_UNLIKELY(!d->getMessageHook)) {
int errorCode = GetLastError();
qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s",
errorCode, qPrintable(qt_error_string(errorCode)));
}
}
我做了研究,错误 Not enough storage is available to process this command.
可能是 OS (Windows) 没有足够的资源来处理这个函数 (SetWindowsHookEx
) 并且创建失败一个钩子,然后 Qt 发出一个致命信号,最后我的应用程序被杀死了。
我在 Windows Server 2019 上对此进行了测试,该应用程序运行良好,没有出现崩溃。
我只是想更多地了解错误消息 (stderr) 的含义,因为我真的不知道什么是“存储空间不足”?我认为这可能是 Windows Server 2016 的限制或错误?如果是,是否有任何方法可以解决 Windows Server 2016 上的这个问题?
当注册表值设置不正确或在最近重置或重新安装后,配置设置不正确时,Windows 服务器中通常会出现“没有足够的存储空间来处理此命令”错误。
以下是针对此问题的验证程序:
- 单击“开始”> 运行 > regedit 并按 Enter
- 找到这个键名HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\LanmanServer\Parameters
- 找到 IRPStackSize
- 如果此值不存在,请右键单击“参数”键并单击“新建”>“双字值”,然后在名称下键入 IRPStackSize。
- 值的名称必须与我上面的完全相同(大小写字母的组合)。
- 右键单击 IRPStackSize,然后单击“修改”
- Select Decimal 输入大于 15 的值(最大值为 50 decimal)并单击 Ok
- 您可以关闭注册表编辑器并重新启动计算机。
经过几天的研究,我终于可以配置 Windows Server 2016 设置(注册表)来防止崩溃。
所以基本上它是 OS 本身的限制,它被称为 desktop heap limitation.
https://docs.microsoft.com/en-us/troubleshoot/windows-server/performance/desktop-heap-limitation-out-of-memory
(有趣的是错误信息是 Not enough storage is available to process this command
但真正的问题是 desktop heap limitation.
)
所以对于解决方案,请按照 link 中的步骤进行:https://docs.microsoft.com/en-us/troubleshoot/system-center/orchestrator/increase-maximum-number-concurrent-policy-instances
我将 SharedSection
的第三个参数增加到 2048
并解决了这个问题。
步骤总结:
non-interactive 桌面的桌面堆由以下注册表值的 SharedSection= 段的第三个参数标识:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SubSystems\Windows
此注册表值的默认数据如下所示:
%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16
要输入到 SharedSection= 段的第三个参数 的值应基于以下计算:
(所需的并发策略数)* 10 =(第三个参数值)
示例:如果希望有 200 个并发策略实例,则 200 * 10 = 2000,四舍五入到一个合适的内存数字为您提供 2048 作为第三个参数,导致对注册表值进行以下更新:
SharedSection=1024,3072,2048
我的项目使用 QTcpSocket
和函数 setSocketDescriptor()
。代码很正常
QTcpSocket *socket = new QTcpSocket();
socket->setSocketDescriptor(this->m_socketDescriptor);
此编码大部分时间都运行良好,直到我 运行 在 Windows Server 2016 上进行性能测试时,崩溃发生了。我使用故障转储进行调试,这是日志
0000004f`ad1ff4e0 : ucrtbase!abort+0x4e
00000000`6ed19790 : Qt5Core!qt_logging_to_console+0x15a
000001b7`79015508 : Qt5Core!QMessageLogger::fatal+0x6d
0000004f`ad1ff0f0 : Qt5Core!QEventDispatcherWin32::installMessageHook+0xc0
00000000`00000000 : Qt5Core!QEventDispatcherWin32::createInternalHwnd+0xf3
000001b7`785b0000 : Qt5Core!QEventDispatcherWin32::registerSocketNotifier+0x13e
000001b7`7ad57580 : Qt5Core!QSocketNotifier::QSocketNotifier+0xf9
00000000`00000001 : Qt5Network!QLocalSocket::socketDescriptor+0x4cf7
00000000`00000000 : Qt5Network!QAbstractSocket::setSocketDescriptor+0x256
在 stderr 日志中,我看到了那些日志
CreateWindow() for QEventDispatcherWin32 internal window failed (Not enough storage is available to process this command.)
Qt: INTERNAL ERROR: failed to install GetMessage hook: 8, Not enough storage is available to process this command.
这是函数,代码在 Qt 代码库中停止
void QEventDispatcherWin32::installMessageHook()
{
Q_D(QEventDispatcherWin32);
if (d->getMessageHook)
return;
// setup GetMessage hook needed to drive our posted events
d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
if (Q_UNLIKELY(!d->getMessageHook)) {
int errorCode = GetLastError();
qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s",
errorCode, qPrintable(qt_error_string(errorCode)));
}
}
我做了研究,错误 Not enough storage is available to process this command.
可能是 OS (Windows) 没有足够的资源来处理这个函数 (SetWindowsHookEx
) 并且创建失败一个钩子,然后 Qt 发出一个致命信号,最后我的应用程序被杀死了。
我在 Windows Server 2019 上对此进行了测试,该应用程序运行良好,没有出现崩溃。
我只是想更多地了解错误消息 (stderr) 的含义,因为我真的不知道什么是“存储空间不足”?我认为这可能是 Windows Server 2016 的限制或错误?如果是,是否有任何方法可以解决 Windows Server 2016 上的这个问题?
当注册表值设置不正确或在最近重置或重新安装后,配置设置不正确时,Windows 服务器中通常会出现“没有足够的存储空间来处理此命令”错误。
以下是针对此问题的验证程序:
- 单击“开始”> 运行 > regedit 并按 Enter
- 找到这个键名HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\LanmanServer\Parameters
- 找到 IRPStackSize
- 如果此值不存在,请右键单击“参数”键并单击“新建”>“双字值”,然后在名称下键入 IRPStackSize。
- 值的名称必须与我上面的完全相同(大小写字母的组合)。
- 右键单击 IRPStackSize,然后单击“修改”
- Select Decimal 输入大于 15 的值(最大值为 50 decimal)并单击 Ok
- 您可以关闭注册表编辑器并重新启动计算机。
经过几天的研究,我终于可以配置 Windows Server 2016 设置(注册表)来防止崩溃。
所以基本上它是 OS 本身的限制,它被称为 desktop heap limitation.
https://docs.microsoft.com/en-us/troubleshoot/windows-server/performance/desktop-heap-limitation-out-of-memory
(有趣的是错误信息是 Not enough storage is available to process this command
但真正的问题是 desktop heap limitation.
)
所以对于解决方案,请按照 link 中的步骤进行:https://docs.microsoft.com/en-us/troubleshoot/system-center/orchestrator/increase-maximum-number-concurrent-policy-instances
我将 SharedSection
的第三个参数增加到 2048
并解决了这个问题。
步骤总结:
non-interactive 桌面的桌面堆由以下注册表值的 SharedSection= 段的第三个参数标识:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SubSystems\Windows
此注册表值的默认数据如下所示:
%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16
要输入到 SharedSection= 段的第三个参数 的值应基于以下计算:
(所需的并发策略数)* 10 =(第三个参数值)
示例:如果希望有 200 个并发策略实例,则 200 * 10 = 2000,四舍五入到一个合适的内存数字为您提供 2048 作为第三个参数,导致对注册表值进行以下更新:
SharedSection=1024,3072,2048