【问题标题】:malloc()/free() in several threads crashes on Windows多个线程中的 malloc()/free() 在 Windows 上崩溃
【发布时间】:2018-08-01 01:25:57
【问题描述】:

简单代码(下面,malloc()/free() 序列在 100 个线程中运行)在我尝试运行的任何 Windows 操作系统上崩溃。

任何帮助将不胜感激。

也许使用一些编译器指令会有所帮助?

我们在 VS2017 中以 Release/x64 构建可执行文件;运行几分钟后,我尝试过的任何 Windows 平台上的可执行文件都会崩溃。

我也尝试使用 VS2015 进行构建,但没有帮助。

同样的代码在 Linux 上运行良好。

其实问题远比看起来严重;我们面临的情况是,我们的服务器代码在生产环境中每天无故崩溃数次(当用户调用次数超过某个值时)。我们试图确定 并创建了重现问题的最简单的解决方案。

使用 VS 项目存档是 here

VS 说命令行是:

/Yu"stdafx.h" /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"x64\Release\vc140.pdb" /Zc:inline /fp:precise /D"NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /Fa"x64\Release\" /EHsc /nologo /Fo"x64\Release\" /Fp"x64\Release\MallocTest.pch"

代码:

#include "stdafx.h"
#include <iostream>
#include <thread>
#include <conio.h>

using namespace std;

#define MAX_THREADS 100

void task(void) {
    while (true) {
        char *buffer;
        buffer = (char *)malloc(4096);
        if (buffer == NULL) {
            cout << "malloc error" << endl;
        }
        free(buffer);
    }
}

int main(int argc, char** argv) {    
    thread some_threads[MAX_THREADS];

    for (int i = 0; i < MAX_THREADS; i++) {
        some_threads[i] = thread(task);
    }

    for (int i = 0; i < MAX_THREADS; i++) {
        some_threads[i].join();
    }

    _getch();
    return 0;
}

【问题讨论】:

  • 您是否与运行时库的线程安全版本链接?
  • @molbdnilo “您是否正在链接运行时库的线程安全版本?”我猜是的,因为命令行中有 /MD 标志:/Yu"stdafx.h" /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"x64\Release\vc140。 pdb" /Zc:inline /fp:precise /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /Fa" x64\Release\" /EHsc /nologo /Fo"x64\Release\" /Fp"x64\Release\MallocTest.pch"
  • 我能够重现这个。即使使用new 也会发生错误(它实际上仍然调用相同的_malloc_base)。调用堆栈以ntdll.dll!RtlpLowFragHeapAllocFromContext(); tdll.dll!RtlpAllocateHeapInternal(); ucrtbase.dll!_malloc_base() 结尾
  • 绝对不是stackoverflow.com/questions/4826479/…的复制品。我可以使用多线程 crt 重现这一点(顺便说一句,在我的 VS2017 上根本没有单线程 crt)。这是ntdll中的崩溃,调用堆栈:ntdll.dll!RtlpLowFragHeapAllocFromContext(); tdll.dll!RtlpAllocateHeapInternal(); ucrtbase.dll!_malloc_base()
  • 你成就了我的一天。 VC2017 100 线程的重现问题。它显示 HeapAlloc 中的访问冲突(在 ntdll.dll 中的某个位置)...有一些愚蠢的错误...或者您在 MS c++ 或 ms windows 中发现了错误...

标签: c++ windows multithreading crash malloc


【解决方案1】:

这是 Windows 低碎片堆的问题。它已在 OS build 19041(2020 年 5 月更新)中得到修复。

【讨论】:

    【解决方案2】:

    在您非常小的 MVCE 中没有任何内容表明编程错误,malloc()free() 应该是线程安全的,cout 上调用的方法也应该是线程安全的。该程序并非设计为永远停止,因此它似乎是在多线程上下文中对malloc() 进行的良好压力测试。

    但是请注意,如果malloc() 失败,尝试将错误报告给cout 是有问题的,这可能会进一步调用malloc() 进行缓冲。建议将错误报告给cerr 或使cout 无缓冲。在任何情况下,malloc() 失败都不会导致崩溃,即使在流方法中也是如此。

    您似乎在 VS 目标平台上链接到的运行时库中发现了一个错误。跟踪程序在崩溃之前的内存使用情况会很有趣。内存使用量的稳步增加也表明运行时库中存在一些问题。该程序一次不会分配超过 MAX_THREADS 的 4K 块,因此内存使用应该保持在很低的水平,低于 2MB,包括与 malloc() 的现代实现使用的基于线程的缓存相关的开销。

    【讨论】:

      猜你喜欢
      • 2014-01-01
      • 2015-05-28
      • 1970-01-01
      • 2012-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-02
      相关资源
      最近更新 更多