3

大量のオブジェクトを作成してベクターに挿入するプログラムがあります。私の考えでは、約 10,000 個のオブジェクトを作成することでしたが、プログラムが数千回後にクラッシュすることがわかりました。クラッシュする前に作成されるオブジェクトの量はランダムであり、コード内の行を変更するかどうかに依存するため、メモリ割り当ての問題に関連していると思います。

私が作成しているオブジェクトは次のとおりです。

class Object {
public:

    //Needed by map
    Object() {

    }

    Object(int newID, std::string newText) {
        id = newID;
        text = newText;
    }

    int getID() {
        return id;
    }

    std::string getText() {
        return text;
    }

    ~Object() {

    }

private:

    int id;
    std::string text;
};

ご覧のとおり、特別なことは何もありません。オブジェクトを作成するプログラムは次のとおりです。

int main(int argc, char** argv) {

int numberOfElements;
long start;
long end;
long time1, time2, time3, time4, time5, time6;


numberOfElements = 7000;  //7000<X<7050  Maximum reliable

{
    //Measuring time for creation of 1000 elements in vector of objects,
    cout << "VECTOR OF OBJECTS:" << endl;
    start = getTimeInMicroseconds();
    vector<Object> vectorOfObjects;
    vectorOfObjects.reserve(10000);
    for (int i = 0; i < numberOfElements; i++) {

        cout << "Creating object " << i << endl;

        Object object = *(new Object(i, "This is object "+i));
        cout << "Created object " << i << endl;

        vectorOfObjects.push_back(object);             
        cout << "Object inserted" << endl;
    }
    end = getTimeInMicroseconds();
    time1 = end - start;

    cout << "- Time to create " << numberOfElements << " objects = "
            << time1 << " microseconds" << endl;
}

return 0;
}

繰り返しますが、非常に単純なことです。クラッシュする前に作成されるオブジェクトの量は、このコードの後に​​何を追加するかによって異なります。2000年以降にクラッシュすることもあれば、4000年以降、7000年後にクラッシュすることもあります...メモリ割り当ての問題だと思いますが、解決方法がわかりません。

オブジェクトを次のように作成しようとしました:

Object object(i, "text");
vectorOfObjects.push_back(object);

vectorOfObjects.push_back(Object(i, "text");
vectorOfObjects.push_back(*(new Object(i, "text")));  

しかし、どれも機能しませんでした。もちろん、ここで示した最後の 2 つの例のように、これらのオブジェクトを動的に作成する方法を好みます。map や deque などのさまざまなコンテナーでも試しましたが、コンテナー自体ではなくオブジェクトの作成が原因で問題が発生するため、どのコンテナーを使用しても問題ありません。

これはコア ダンプです。

-bash-3.2$ pstack core
core 'core' of 5884:    ./datastructuresperformance
 d147646c strlen   (8046eb8, 8055000, 8046ebc, d17c34ed) + c
 08051fdf main     (1, 8047264, 804726c, 8051ddf) + f7
 08051e27 _start   (1, 80473b8, 0, 80473d4, 80473ef, 8047441) + 67


-bash-3.2$ pmap core
core 'core' of 5884:    ./datastructuresperformance
08044000      16K rwx--    [ stack ]
08050000      20K r-x--  /export/home/dcs/SolStudioProjects/DataStructuresPerformance/dist/Release/OracleSolarisStudio-Solaris-x86/datastructuresperformance
08064000       8K rwx--  /export/home/dcs/SolStudioProjects/DataStructuresPerformance/dist/Release/OracleSolarisStudio-Solaris-x86/datastructuresperformance
08066000     280K rwx--    [ heap ]
D1450000    1088K r-x--  /lib/libc.so.1
D1560000      32K rwx--  /lib/libc.so.1
D1568000       8K rwx--  /lib/libc.so.1
D1570000     292K r-x--  /lib/libm.so.2
D15C8000      16K rwx--  /lib/libm.so.2
D15D0000      48K r-x--  /usr/lib/libCrun.so.1
D15EB000       8K rwx--  /usr/lib/libCrun.so.1
D15ED000      20K rwx--  /usr/lib/libCrun.so.1
D1600000      24K rwx-- 
D1610000    1244K r-x--  /usr/lib/libCstd.so.1
D1750000       4K rwx-- 
D1756000     216K rwx--  /usr/lib/libCstd.so.1
D1790000       4K rwx-- 
D17A0000       4K rw--- 
D17B0000       4K rw--- 
D17BF000     176K r-x--  /lib/ld.so.1
D17F0000       4K rwx-- 
D17FB000       8K rwx--  /lib/ld.so.1
D17FD000       8K rwx--  /lib/ld.so.1
 total      3532K

これまでのところ、このプログラムが使用する最大メモリ量は、このマシンの 1GB よりもはるかに少ないため、メモリ量に関連する問題ではありません。

4

3 に答える 3

12
  1. *new T()メモリ リーク オペレータと呼ばれています。オブジェクトを動的に割り当てたくはありません。代わりに、オブジェクトを構築したいだけです(ベクトルで破壊されます)
  2. (つまり)"string" + iでポインター演算を行うため、使用できません。論理的に言うと、が文字列リテラルの長さよりも大きい場合、未定義の動作 (この場合はクラッシュ) が発生します。char(&)[7]"string""string" + i&("string"[i])i

new何をしているのかわからない限り、C++ で使用しないでください。

Object object = Object(i, "This is object " + to_string(i));

emplace_backさらに良いことに、コンパイラがそれほど古くない場合は、使用を検討してください。

    vector<Object> vectorOfObjects;
    vectorOfObjects.reserve(100000000ul);
    for(int i = 0; i < numberOfElements; i++) {
        vectorOfObjects.emplace_back(i, "This is object " + to_string(i));
    }
于 2013-11-01T17:12:40.760 に答える
5

(すみません、その行に少しびっくりしました:/)

Object object = *(new Object(i, "This is object "+i));

そうしないでください。これまで。代わりにこれを試してください:

Object object(i,"This is object");

その行には2つの問題があります:

a) あなたが実際にしたことは、オブジェクトを作成し、それをコピーして、それを忘れることでした。

b) (これがコードをクラッシュさせた原因です) -文字列 "This is Object " よりバイト先の場所から始まる文字列を指定します。iご想像のとおり、その記憶は自由に読めるものではありません。

于 2013-11-01T17:12:59.927 に答える
-1

すでに出されている回答に加えて、シンプルに保つことをお勧めします。ほとんどの場合reserve、割り当て戦略は一般に優れたパフォーマンスを提供するため、ベクターのサイズを変更する必要はありません。段階的に作業し、コードをプロファイリングしてから、さらにステートメントを追加することを決定します。

私が特にこれについてコメントする理由は、それがより大きな病気、つまり時期尚早の最適化の兆候だからです。

テストには次のコードを使用しました。

#include<string>
#include<vector>
#include<iostream>

#include<boost/timer/timer.hpp>

class Object {
 public:
  Object() { }
  Object(int id, const std::string& text)
      : m_id(id),
        m_text(text) { }
  int id() const {
    return m_id;
  }
  std::string text() const {
    return m_text;
  }
 private:
  int m_id;
  std::string m_text;
};

int main(int argc, char* argv[]) {
  size_t N = std::stoi(argv[1]); // add argc check
  std::vector<Object> objects;
  //objects.reserve(N);
  {
    boost::timer::auto_cpu_timer t;
    for(size_t k=0; k<N; k++) {
      //objects.emplace_back(Object(k, "random text"));
      objects.push_back(Object(k, "random text"));
    }
    std::cout<<"Objects in container: "<<objects.size()<<std::endl;
  }
}

g++ example.cpp -std=c++11 -O2そして、私のマシン ( GCC 4.8.1 を使用する OS X 10.7.4 上)の最適化されたコードでは、次の結果が得られます (秒単位の経過時間N=1,000,000):

           Push Emplace
   Reserve 0.078 0.078
No Reserve 0.087 0.087

先に進んでムーブ コンストラクターの定義を開始し、必要なすべてを最適化することもできますが、通常は、より単純なコードの方がパフォーマンスが高くなります。

于 2013-11-01T17:50:24.667 に答える