2
#include <iostream>
#include <cassert>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <Windows.h>

using namespace std;

char randomLetter()
{
    srand(time(0));
    char rValue;

    while(1)
    if((rValue=(rand()/129)) > 31) 
        return rValue;
}


int main()
{       
    vector<char> meegaString;

    for(int i=0; i < 10000000000; i++)
    {   
        meegaString.push_back(randomLetter());

                if(!(i%10000000)) 
            cout<<"There are: " <<i+1<<" chars in the list"<<endl;

    }

    system("pause");
    return 0;
}

このプログラムを実行する前の RAM 使用量は、約 2500/8000 MB でした。3200 になると、次の例外がスローされます。

リソース gormandizer.exe の 0x773c15de で未処理の例外: Microsoft C++ 例外: std::bad_alloc メモリ位置 0x0045f864..

1) 64 ビット OS で動作しているのに、このプログラムが使用可能なメモリ全体を満たしていないのはなぜですか?

2) プロセッサー (インテル Core i5) の 26% しか使用されていないのはなぜですか?

4

3 に答える 3

4
  1. 前述のように、ベクトルの要素は連続して格納されます。また、の実装で使用されているメモリ割り当てアルゴリズムによっては、std::vector事前にメモリを事前に割り当てようとしている可能性があります。malloc/new呼び出しの数を減らすために使用されているよりも多くのメモリを割り当てます。そのため、32ビットOSがサポートできるよりも多くのメモリを要求するようになる可能性があります(これにより、64ビットプロセスが機能する理由が説明されますが、十分なメモリがあるにもかかわらず、32ビットプロセスは機能しません。利用可能)。

  2. プロセスは4つのうち1つのコアで実行されており、非常にビジーであるため、CPU時間の約25%を占めています。他のプロセスが残りを構成します。

参照:ベクトルメモリ割り当てについて賢くする

于 2012-06-14T13:14:05.100 に答える
2

anthony-arnold の答えは間違っていません。彼の言い回しを少し自由にすれば、まだ何かが欠けています。

他の人が言及したように、Core i5 がクアッドコアの場合 (すべて i5 のクアッドコアですか?)、25% はコアの 1 つ (つまり、プロセスが実行されていたコア) がほぼ 100% ビジーであることを示唆している可能性があります。他の人はほとんどアイドル状態です。anthony-arnold の回答とは対照的に、25% は他のプロセスが他の 75% を占有していることを示しているわけではなく、利用可能な CPU 時間の残りの 75% が単に無駄になっている (アイドル) ことを示しています。繰り返しになりますが、CPU がクアッド コアで、マルチスレッド テスト アプリケーションがなければ、テスト アプリは全体の 25% 以上を消費することはできません。

メモリ割り当ての断片化やその他のオーバーヘッドを差し引いて、メモリ空間の枯渇を探していたなら、あなたはそれを見つけました。他の人が示唆したように、アプリは 32​​ ビット アプリとしてビルドされているようです。64 ビット OS で実行されている場合でも、アプリは 32​​ ビット アドレス空間が保持できる上限である 4Gb を超えてアドレス指定することはできません。それでも、OS用に予約された仮想アドレス空間、プログラムと共有ライブラリ空間、スタック空間、他のものに割り当てられたヒープ空間、ヒープ空間のオーバーヘッドなど、他にも多くのオーバーヘッドがあります。そのため、meegaString ベクトルは完全な 4Gb に近づくことはなく、おそらく 2Gb にも近づくことはありません (大規模なアドレス空間を認識するアプリとして構築された場合、おそらく 2Gb を少し超える可能性があります)。

anthony-arnold が言及している「フォワード アロケーション」ポイントに関しては、次のとおりです。すべての STL コンテナーは、償却された操作時間について約束します。std::vector クラスは、平均して (つまり、償却されて)、push_back() 操作が一定時間 (つまり、O(1)) になることを約束します。実行に時間がかかることはありません (もしそうなら、それは O(n) になります)。ときどき、push_back() を実行するのに O(1) よりもはるかに時間がかかることがあります。これは、push_back() によってコンテナーのデータが現在割り当てられているスペースを超えてしまうことがあり、再割り当てを実行して現在のコンテンツを次の場所に移動する必要があるためです。新しい場所を削除し、その古い内容を削除します。OSの連携により、適切に実装されたカスタム作成の STL 実装は、実際に内容を移動する必要がないように、仮想メモリと MMU を使用してトリックを実行することにより、それよりもさらに優れた機能を実行できます。OS に MMU にデータを作成するよう指示するだけです。仮想メモリ ページは新しい場所にマップされますが、これはまったく別の問題であり、バックグラウンドで発生するため、とにかく心配する必要はありません。いずれにせよ、はい、std::vector クラスは、新しい割り当てを行うたびに、必要なメモリ ブロックよりも大きなメモリ ブロックを「事前に割り当て」なければなりません。これが、O(1) push_back() 時間を約束できる唯一の方法だからです。push_back() を実行するたびにコンテンツを新しく割り当てられたバッファーに移動する必要がある場合、push_back() の時間計算量は O(1) ではなく O(n) になります。

于 2012-06-15T15:41:12.197 に答える
0

ベクトルクラステンプレートは動的配列を実装しますが、これには連続したメモリブロックが必要です。

トピックを閉じるには、この目的のために リストコンテナを使用できますが、スタックが最善の解決策のようです。ただし、リストまたはスタックのいずれでも、同じエラー(現在は4600 MB近く)でクラッシュします。見た目は似ていますが、無効なデータ構造が選択されたことが原因ではありません。これは、32ビットアプリケーションで使用可能な非常に制限されたメモリがあるために発生します。したがって、完全に詰め込むには、このプログラムをx64プラットフォームでコンパイルします。

#include <iostream>
#include <stack>
#include <ctime>
#include <cstdlib>


using namespace std;

char randomLetter()
{
    srand(time(0));
    char rValue;

    while(1)
    if((rValue=(rand()/129)) > 31) 
        return rValue;
}


int main()
{       
    stack<char> meegaString;

    for(int i=0; i < 10000000000; i++)
    {   
        meegaString.push(randomLetter());

                if(!(i%10000000)) 
            cout<<"There are: " <<i+1<<" chars in the list"<<endl;

    }




    system("pause");
    return 0;
}
于 2012-06-14T13:56:04.207 に答える