当调整大小时,`std::vector` 抛出 "bad allocation" 异常

5

我有以下C++ dll代码,我通过JNI调用它:

std::vector<double> myVector;
myVector.resize(10000000, 0);

尽管向量的最大大小据说比10000000更大,但我仍然遇到了“bad allocation”的异常。

为了定位任何内存泄漏,我应该使用哪个工具来跟踪内存分配?

如果真的没有内存泄漏,我该如何减少向量的占用空间以确保有足够的空间?


1
我的猜测是,这可能是堆损坏或STL实现中的错误。您是否检查过系统上是否仍有80 MB可用? - cmaster - reinstate monica
你不能这样做。vector需要内存是连续的。如果没有足够的连续内存,你会遇到问题并得到一个异常。你需要使用其他容器,如std::list。但是10000000个double并不算太多(80Mo),所以我很惊讶它失败了。可能与JNI有关? - Davidbrcz
@cmaster 是的,我有80 MB可用。 - uahakan
@Davidbrcz 我该如何检查是否有80MB的连续可用内存?或者我该如何调试这个问题?也许你能推荐一个性能分析工具吗? - uahakan
你的系统是32位的吗?因为在64位系统上,地址空间碎片化不应该成为问题。你可能想要检查一下是否仍然可以分配一个这样大小的原始数组 new double[10*1000*1000] 来排除 vector<> 实现中的问题,然后再尝试分配2000个大小为4kiB的数组 new double[512]。如果后者失败了,那么你就没有足够的内存,如果成功了,那么你就有一个内存碎片化的问题。 - cmaster - reinstate monica
1个回答

1

我知道这可能是最糟糕的解决方案,用来确定您的分配大小。所以,让我们开始吧:

main.cpp:

#include "jni.h"
#include <vector>
#include <iostream>

#if (_MSC_VER == 1800) || (__cplusplus >= 201103L)
    #include <thread>
    #include <chrono>
#elif _MSC_VER
    #include <windows.h>
#else
    #include <unistd.h>
#endif


extern "C" JNIEXPORT void Java_test_Test_Alloc(JNIEnv* env, jobject obj, jint max_size, jint increment_size)
{
    std::vector<double> vec;
    size_t isize = max_size / 4;
    size_t oldsize = isize;

    while(isize <= max_size)
    {
        try
        {
            vec.resize(isize, 0);
            oldsize = isize;
            isize += increment_size;
            std::cout<<"Allocated: "<<vec.size() * sizeof(double)<<" bytes.\n";
        }
        catch (std::bad_alloc &e)
        {
            std::cout<<"Failed to allocate: "<<isize * sizeof(double)<<" bytes.\n";
            std::cout<<"Approx. max size: "<<oldsize * sizeof(double)<<" bytes.\n";
            std::cout<<"Exception: "<<e.what()<< "\n";
            std::cout<<"Vector.Max_Size(): "<<vec.max_size()<< "\n";
            break;
        }

        #if (_MSC_VER == 1800) || (__cplusplus >= 201103L)
            std::this_thread::sleep_for(std::chrono::seconds(1));
        #elif _MSC_VER
            Sleep(1);
        #else
            sleep(1);
        #endif
    }
}

#if defined _WIN32 || defined _WIN64
#include <windows.h>

extern "C" __declspec(dllexport) bool __stdcall DllMain(HINSTANCE hinstDLL, unsigned fdwReason, void* lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            break;

        case DLL_PROCESS_DETACH:
            break;
    }
    return true;
}
#endif

在Java端(Test.java)上:

package test;

public class Test {

    static {
        System.loadLibrary("JNITest");
    }

    public static native void Alloc(int max_size, int increment_size);

    public static void main(String[] args) {
        Alloc(100000000, 50000);
    }

}

对我而言,它会打印出:
Allocated: 200000000 bytes.
Allocated: 200400000 bytes.
Allocated: 200800000 bytes.
.
.
.
Allocated: 399600000 bytes.
Allocated: 400000000 bytes.
Failed to allocate: 400400000 bytes.
Approx. max size: 400000000 bytes.
Exception: std::bad_alloc
Vector.Max_Size(): 536870911

就像我说的一样,这是一种不好的“猜测”分配多少资源的方式,但在这种情况下,没有其他人发布任何内容,所以我将把它留在这里,如果您愿意,可以使用它。


我会尝试并告诉您结果。非常感谢。 - uahakan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接