Golang在32位Windows系统中创建新OS线程失败及runtime.newosproc致命错误问题
Golang在32位Windows系统中创建新OS线程失败及runtime.newosproc致命错误问题 首先,我并非专业的开发人员或程序员,因此如果我的解释有任何不足之处,敬请谅解。我在运行用Golang编写的Syncthing时遇到了这个问题。
基本上,程序因以下错误而崩溃:
runtime: failed to create new OS thread (have 1192 already; errno=8)
Panic at 2020-10-28T21:25:20+09:00
fatal error: runtime.newosproc
runtime stack:
runtime.throw(0x120fa12, 0x11)
runtime/panic.go:1116 +0x64
runtime.newosproc(0x17ecafc0)
runtime/os_windows.go:794 +0x146
runtime.newm1(0x17ecafc0)
runtime/proc.go:1829 +0xbd
runtime.newm(0x13e5b7c, 0x12c2c000, 0x4a7, 0x0)
runtime/proc.go:1808 +0x81
runtime.startm(0x12c2c000, 0x1)
runtime/proc.go:1965 +0xac
runtime.handoffp(0x12c2c000)
runtime/proc.go:2004 +0x28c
runtime.retake(0x68d8ec28, 0x4587, 0x0)
runtime/proc.go:4805 +0x171
runtime.sysmon()
runtime/proc.go:4713 +0x275
runtime.mstart1()
runtime/proc.go:1172 +0x9b
runtime.mstart()
runtime/proc.go:1137 +0x51
Syncthing的完整恐慌日志可在 https://github.com/syncthing/syncthing/files/5452199/panic-20201028-212520.log 获取。
我已在Syncthing的问题跟踪器上报告了此问题,但开发人员表示这可能是Go运行时或操作系统的问题,因此我在此提问。
我猜测这可能与此处解释的32位Windows中每个进程2000个线程的限制有关,但我无法确认这一点。崩溃确实发生在Syncthing运行于Windows 10 Enterprise LTSB 2016 x86(即32位Windows)下的情况。
这个问题是可以在Syncthing或Go运行时中修复/预防的,还是在32位Windows下运行Go应用程序的固有限制?在上面链接的博客文章中,微软提到了调整代码以“挤入”更多线程,但我不知道这如何对应到用Go编写的代码。
参考: github .com/syncthing/syncthing/issues/7064 github .com/golang/go/issues/42253
更多关于Golang在32位Windows系统中创建新OS线程失败及runtime.newosproc致命错误问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang在32位Windows系统中创建新OS线程失败及runtime.newosproc致命错误问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这是一个典型的32位Windows系统线程限制问题。错误信息显示已经创建了1192个线程,而32位Windows每个进程默认限制为2000个线程(包括系统线程)。Go运行时需要创建新的OS线程来处理goroutine,但达到了系统限制。
主要原因是32位Windows的地址空间有限(2GB用户空间),每个线程需要分配栈空间(默认1MB),大量线程会快速耗尽地址空间。虽然可以通过编译选项调整,但根本解决方法是减少线程使用或迁移到64位系统。
以下是一些可能的代码调整方案:
- 减少GOMAXPROCS:
func main() {
// 在程序启动时设置最大CPU使用数
runtime.GOMAXPROCS(2)
// 其他初始化代码...
}
- 调整栈大小(编译时):
# 使用更小的栈大小编译
go build -ldflags "-s -w -extldflags=-Wl,--stack,1048576"
- 控制并发goroutine数量:
// 使用工作池限制并发
type WorkerPool struct {
maxWorkers int
semaphore chan struct{}
}
func NewWorkerPool(max int) *WorkerPool {
return &WorkerPool{
maxWorkers: max,
semaphore: make(chan struct{}, max),
}
}
func (wp *WorkerPool) Execute(task func()) {
wp.semaphore <- struct{}{}
go func() {
defer func() { <-wp.semaphore }()
task()
}()
}
// 使用示例
func main() {
pool := NewWorkerPool(100) // 限制最多100个并发goroutine
for i := 0; i < 1000; i++ {
pool.Execute(func() {
// 执行任务
})
}
}
- 监控线程使用:
func monitorThreads() {
for {
var count int32
runtime.ReadMemStats(&memStats)
// 可以通过外部工具监控线程数
time.Sleep(5 * time.Second)
}
}
然而,这些方法都只是缓解措施。在32位Windows上,当应用程序需要大量并发时,最终还是会遇到这个限制。Syncthing作为文件同步工具,可能需要处理大量并发连接和文件操作,特别容易触发此限制。
根本解决方案是:
- 升级到64位Windows系统
- 如果必须使用32位系统,考虑减少Syncthing的并发操作数量
- 调整系统注册表增加线程限制(风险较高):
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Executive]
"AdditionalDelayedWorkerThreads"=dword:00000040
"AdditionalCriticalWorkerThreads"=dword:00000020
这个问题不是Syncthing或Go运行时的bug,而是32位Windows平台的固有架构限制。Go运行时只是达到了操作系统允许的最大线程数。在64位系统上,这个限制会高得多(通常受可用内存限制)。

