6

以下のテストケースでは、OpenMPを使用した場合の「postMT section」メッセージに続くループで、32ビットマシン(std :: bad_allocをスロー)のメモリが不足していますが、OpenMPの#pragmasがコメントアウトされている場合、コードは実行されます。正常に完了するまで、メモリが並列スレッドで割り当てられている場合、メモリが正しく解放されず、メモリが不足しているように見えます。

問題は、以下のメモリ割り当てと削除コードに何か問題があるのか​​、それともgccv4.2.2またはOpenMPのバグなのかということです。gcc v4.3も試しましたが、同じ失敗になりました。

int main(int argc, char** argv)
{
    std::cout << "start " << std::endl;

    {
            std::vector<std::vector<int*> > nts(100);
            #pragma omp parallel
            {
                    #pragma omp for
                    for(int begin = 0; begin < int(nts.size()); ++begin) {
                            for(int i = 0; i < 1000000; ++i) {
                                    nts[begin].push_back(new int(5));
                            }
                    }
            }

    std::cout << "  pre delete " << std::endl;
            for(int begin = 0; begin < int(nts.size()); ++begin) {
                    for(int j = 0; j < nts[begin].size(); ++j) {
                            delete nts[begin][j];
                    }
            }
    }
    std::cout << "post MT section" << std::endl;
    {
            std::vector<std::vector<int*> > nts(100);
            int begin, i;
            try {
              for(begin = 0; begin < int(nts.size()); ++begin) {
                    for(i = 0; i < 2000000; ++i) {
                            nts[begin].push_back(new int(5));
                    }
              }
            } catch (std::bad_alloc &e) {
                    std::cout << e.what() << std::endl;
                    std::cout << "begin: " << begin << " i: " << i << std::endl;
                    throw;
            }
            std::cout << "pre delete 1" << std::endl;

            for(int begin = 0; begin < int(nts.size()); ++begin) {
                    for(int j = 0; j < nts[begin].size(); ++j) {
                            delete nts[begin][j];
                    }
            }
    }

    std::cout << "end of prog" << std::endl;

    char c;
    std::cin >> c;

    return 0;
}
4

3 に答える 3

3

最初のOpenMPループを1000000から2000000に変更すると、同じエラーが発生します。これは、メモリ不足の問題がOpenMPスタック制限にあることを示しています。

OpenMPスタック制限をbashで無制限に設定してみてください

ulimit -s unlimited

OpenMP環境変数OMP_STACKSIZEを変更して、100MB以上に設定することもできます。

更新1:最初のループを次のように変更します

{
    std::vector<std::vector<int*> > nts(100);
    #pragma omp for schedule(static) ordered
    for(int begin = 0; begin < int(nts.size()); ++begin) {
        for(int i = 0; i < 2000000; ++i) {
            nts[begin].push_back(new int(5));
        }
    }

    std::cout << "  pre delete " << std::endl;
    for(int begin = 0; begin < int(nts.size()); ++begin) {
        for(int j = 0; j < nts[begin].size(); ++j) {
            delete nts[begin][j]
        }
    }
}

次に、メインスレッドのi=1574803でメモリエラーが発生します。

更新2:インテル®コンパイラーを使用している場合は、コードの先頭に以下を追加すると、問題が解決します(余分なオーバーヘッドに十分なメモリーがある場合)。

std::cout << "Previous stack size " << kmp_get_stacksize_s() << std::endl;
kmp_set_stacksize_s(1000000000);
std::cout << "Now stack size " << kmp_get_stacksize_s() << std::endl;

更新3:完全を期すために、別のメンバーが述べたように、数値計算を実行する場合は、OpenMPを使用して1000000の割り当てを行うのではなく、すべてを1つの新しいfloat[1000000]に事前に割り当てるのが最善です。これは、オブジェクトの割り当てにも当てはまります。

于 2010-12-02T15:51:20.727 に答える
3

この問題は、OpenMPを使用せずに、pthreadを使用するだけで他の場所で見られることがわかりました。マルチスレッド時の余分なメモリ消費は、標準のメモリアロケータの一般的な動作のようです。Hoardアロケーターに切り替えることで、余分なメモリ消費がなくなります。

于 2010-12-03T12:04:20.047 に答える
0

なぜint*内部ベクトルメンバーとして使用しているのですか?これは非常に無駄です。4バイト(厳密には)のデータと、エントリsizeof(int)ごとに2〜3倍のヒープ制御構造があります。vectorを使用してこれを試してみて、vector<int>より適切に動作するかどうかを確認してください。

私はOpenMPの専門家ではありませんが、この使用法は非対称性が奇妙に思えます。ベクトルを並列セクションに入力し、非並列コードでクリアします。それが間違っているかどうかはわかりませんが、「気分が悪い」のです。

于 2010-12-02T15:18:53.273 に答える