2

自動生成されたC++ソ​​ースファイルがあり、サイズは約40MBです。これは主に、プッシュされるいくつかのベクトルと文字列定数のpush_backコマンドで構成されています。

このファイルをコンパイルしようとすると、g ++が終了し、十分な仮想メモリ(約3 GB)を予約できなかったと表示されます。この問題をグーグルで調べてみると、コマンドラインスイッチを使用すると

--param ggc-min-expand=0 --param ggc-min-heapsize=4096

問題を解決する可能性があります。ただし、これらは最適化がオンになっている場合にのみ機能するようです。

1)これは本当に私が探している解決策ですか?

2)または、これを行うためのより速く、より良い(コンパイルにはこれらのオプションを利用して時間がかかる)方法はありますか?

幸運をお祈りしています、

アレクサンダー

更新:すべての良いアイデアをありがとう。私はそれらのほとんどを試しました。いくつかのpush_back()操作の代わりに配列を使用すると、メモリ使用量が削減されましたが、コンパイルしようとしたファイルが非常に大きいため、後でクラッシュしました。ある意味、このような設定では最適化するものがあまりないため、この動作は非常に興味深いものです。GCCは、メモリを大量に消費する舞台裏で何をしているのでしょうか。(私はすべての最適化も非アクティブ化してコンパイルし、同じ結果を得ました)

ここで切り替えた解決策は、を使用して元のファイルから作成したバイナリオブジェクトファイルから元のデータを読み込むことですobjcopy。これは私が最初はやりたくなかったことです。なぜなら、C ++でこれを行うよりも、高水準言語(この場合はPerl)でデータ構造を作成する方が便利だったからです。

ただし、これをWin32で実行することは、予想よりも複雑でした。objcopyはELF形式のファイルを生成しているようで、出力形式を手動でに設定すると、問題のいくつかが解消されたようpe-i386です。オブジェクトファイル内のシンボルは、標準でファイル名にちなんで名付けられています。たとえば、ファイルinbuilt_training_data.binを変換すると、binary_inbuilt_training_data_bin_startとbinary_inbuilt_training_data_bin_endの2つのシンボルになります。これらのシンボルをとして宣言する必要があると主張するチュートリアルをWebで見つけましたextern char _binary_inbuilt_training_data_bin_start;が、これは正しくないようです-extern char binary_inbuilt_training_data_bin_start;私のためだけに機能しました。

4

6 に答える 6

4

代わりに定数データテーブルを使用する方がよい場合があります。たとえば、これを行う代わりに:

void f() {
    a.push_back("one");
    a.push_back("two");
    a.push_back("three");
    // ...
}

これを試してみてください:

const char *data[] = {
    "one",
    "two",
    "three",
    // ...
};

void f() {
    for (size_t i = 0; i < sizeof(data)/sizeof(data[0]); i++) {
        a.push_back(data[i]);
    }
}

push_back()コンパイラは、多くの呼び出しを含む巨大な関数よりも、大きな定数データテーブルを生成する方がはるかに効率的である可能性があります。

于 2009-11-30T00:02:57.813 に答える
1

40 MB 相当の C++ を生成せずに同じ問題を解決できますか? これは、私が使用したいくつかのオペレーティング システムを超えています。おそらくループといくつかのデータファイルでしょうか?

于 2009-11-30T00:04:17.907 に答える
1

自動生成されたアプリは次のようになります。

push_back(data00001);
...
push_back(data99999);

データを外部ファイルに入れて、プログラムにこのデータをループで読み取らせてみませんか?

于 2009-11-30T00:04:53.130 に答える
0

const char[]ここでの回答のいくつかを補完するために、 'sで構成されるファイルをコンパイルするよりも、バイナリオブジェクトファイルを生成して直接リンクする方がよい場合があります。

最近、gccで同様の問題が発生しました。(約60 MBのPNGデータが約100個のヘッダーファイルに分割されます。)それらすべてを含めることは最悪のオプションです。必要なメモリの量は、コンパイルユニットのサイズとともに指数関数的に増加するようです。

于 2009-11-30T00:21:40.850 に答える
0

コードをリファクタリングできない場合は、オペレーティングシステムが大きなアドレス空間をサポートしていれば、使用しているスワップ領域の量を増やすことができます。これは64ビットコンピューターでは機能するはずですが、32ビットシステムでは3ギガバイトでは多すぎる可能性があります。

于 2009-11-30T01:38:01.283 に答える
0

一連の呼び出しのパンチを生成するだけの場合はpush_back()、次のようにリファクタリングできます。

// Old code:
v.push_back("foo");
v.push_back("bar");
v.push_back("baz");

// Change that to this:
{
    static const char *stuff[] = {"foo", "bar", "baz"};
    v.insert(v.end(), stuff, stuff + ARRAYCOUNT(stuff));
}

マクロARRAYCOUNTは次のように定義されています。

#define ARRAYCOUNT(a) (sizeof(a) / sizeof(a[0]))

余分なレベルの中括弧は、そのようなブロックが多数ある場合に名前の競合を避けるためのものです。stuffまたは、プレースホルダーの新しい一意の名前を生成することもできます。

それでも問題が解決しない場合は、ソース ファイルを多数の小さなソース ファイルに分割することをお勧めします。多くの個別の関数がある場合、これは簡単です。巨大な機能が 1 つある場合は、もう少し努力する必要がありますが、それでも非常に実行可能です。

于 2009-11-30T00:05:15.707 に答える