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")));  

但他们都没有工作。当然,我更喜欢动态创建这些对象的方法,就像我在这里展示的最后两个示例一样;我也尝试了不同的容器,例如 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");

该行有两点错误:

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在 OS X 10.7.4 上使用 GCC 4.8.1),我得到以下结果(以秒为单位的挂墙时间N=1,000,000):

           Push Emplace
   Reserve 0.078 0.078
No Reserve 0.087 0.087

您可以继续并开始定义移动构造函数,并优化您想要的所有内容,但一般来说,更简单的代码通常性能良好。

于 2013-11-01T17:50:24.667 回答