为什么抓不到OOM异常?

Why can't I catch the OOM exception?

我有一个读取大文件以填充 QStringList 的函数。程序崩溃可能是因为内存不足,因为如果我使用小文件,程序运行良好。我尝试通过捕获异常来调试问题。

QStringList readlargefile(QString filename)
{
    QStringList result;
    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly))
    {
        qDebug()<<"cannot open file: "<<filename;
        return result;
    }
    QTextStream in(&file);
    in.setCodec("UTF-8");
    QString line;

    while(in.readLineInto(&line))
    {
        if(!line.isEmpty())
            result<<line;
    }

    file.close();
    return result;
}


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QStringList result;
    try
    {
        qDebug()<<"reading file";
        result=readlargefile("largefile.txt");
    }
    catch(...) {
        qFatal("got exception");
    }
}

输出为:

reading file
Killed

我无法捕获异常,为什么?

如果您的程序被 OS 中止,它不会产生任何异常。但是你可以设置一个信号处理程序:

void signalHandler(int)
{
    //...
}

int main(int argc, char* argv[])
{
    signal(SIGINT  , signalHandler);
    signal(SIGTERM , signalHandler);
#ifdef Q_OS_WIN
    signal(SIGBREAK, signalHandler);
#endif

你无法捕捉到 std::bad_alloc 的原因是因为 Qt 可能使用 ::new 的 no-throw 版本。或者 new 可以,但公主在另一座城堡里。

您可能会在最初的问题(崩溃)中遇到两个陷阱。

1.这可能是一个重新分配问题。

当数组已经填满,并且您尝试插入更多时,它会分配一个新数组并从前一个数组复制(移动)数据。所以在复制(移动)完成之前,你最终会得到两个大数组。如果您知道前面字符串的确切数量,您可以尝试预先分配数组以确保不会重新分配。为此使用 QList::reserve()

2。像 QList 和 QVector 这样的 Qt 容器可以容纳不超过 2GB 的数据。

如果sizeof(QString)是8个字节,则最多允许2^28个项目。

如果你尝试存储更多,它最终会崩溃。尝试 std::vector(使用 reserve)并检查它是否有效。

毕竟,如果您的系统没有足够的内存来执行任务 - 它没有足够的内存,除了更改算法之外您无能为力。