C++;大数据的程序内存不足 我试图解决我在C++程序中写的一个问题。我的内存基本上用完了。该程序是一个缓存模拟器。有一个文件预先收集了内存地址,如下所示:

C++;大数据的程序内存不足 我试图解决我在C++程序中写的一个问题。我的内存基本上用完了。该程序是一个缓存模拟器。有一个文件预先收集了内存地址,如下所示:,c++,memory,allocation,C++,Memory,Allocation,线程地址类型大小指令指针 0 0x7fff60000000 1 8 0x7f058c482af3 这样的条目可能有1000-5000亿条。首先,我尝试读取所有这些条目并将其存储在向量中。同样在阅读时,我建立了一组这些地址(使用map),并存储特定地址的序列号。序列号只是指地址条目在文件中的位置(一个地址可以多次看到)。对于较大的输入,程序在执行此操作时失败,在大约第3000万个条目处出现错误。我想我的记性快用完了。请告知我如何规避这个问题。是否有其他方法来处理此类大数据。非常感谢你!抱歉发了这么

线程地址类型大小指令指针
0 0x7fff60000000 1 8 0x7f058c482af3

这样的条目可能有1000-5000亿条。首先,我尝试读取所有这些条目并将其存储在向量中。同样在阅读时,我建立了一组这些地址(使用map),并存储特定地址的序列号。序列号只是指地址条目在文件中的位置(一个地址可以多次看到)。对于较大的输入,程序在执行此操作时失败,在大约第3000万个条目处出现错误。我想我的记性快用完了。请告知我如何规避这个问题。是否有其他方法来处理此类大数据。非常感谢你!抱歉发了这么长的邮件。我想给出一些上下文和我正在编写的实际代码

以下是相关代码。ParseTaceFile()读取每一行并调用 StoreTokens(),它获取地址和大小,并调用AddAddress(),它实际将地址存储在向量和映射中。下面也给出了类声明。AddAddress()中的第一个try块实际上抛出了bad_alloc异常

void AddressList::ParseTraceFile(const char* filename) {
  std::ifstream in_file;
  std::cerr << "Reading Address Trace File..." << std::endl;
  in_file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
  char *contents = NULL;
  try {
    in_file.open(filename, std::ifstream::in | std::ifstream::binary);
    in_file.seekg(0, std::ifstream::end);
    std::streampos length(in_file.tellg());
    if (length < 0) {
      std::cerr << "Can not read input file length" << std::endl;
      throw ExitException(1);
    }
    contents = (new char[length]);
    in_file.seekg(0, std::ifstream::beg);
    in_file.read(contents, length);
    in_file.close();
    uint64_t linecount = 0, i = 0, lastline = 0, startline = 0;
    while (i < static_cast<uint64_t>(length)) {
      if ((contents[i] == '\n') or (contents[i] == EOF)) {
        contents[i] = '\0';
        lastline = startline;
        startline = i + 1;
        ++linecount;
        if (linecount > 1) {
          StoreTokens((contents + lastline), &linecount);
        }
      }
      ++i;
    }
  } catch (std::bad_alloc& e) {
    delete [] contents;
    std::cerr << "error allocating memory while parsing" << std::endl;
    throw;
  } catch (std::ifstream::failure &exc1) {
    if (!in_file.eof()) {
      delete[] contents;
      std::cerr << "error in reading address trace file" << exc1.what()
          << std::endl;
      throw ExitException(1);
    }
  }
  std::cerr << "Done" << std::endl;
}
//=========================================================    
void AddressList::StoreTokens(char* line, uint64_t * const linecount) {
  uint64_t address, size;
  char *token = strtok(line, " \t");
  uint8_t tokencount = 0;
  while (NULL != token) {
    ++tokencount;
    switch (tokencount) {
    case 1:
      break;
    case 2:
      address = strtoul(token, NULL, 16);
      break;
    case 3:
      break;
    case 4:
      size = strtoul(token, NULL, 0);
      break;
    case 5:
      break;
    default:
      break;
    }
    token = strtok(NULL, " \t");
  }
  AddAddress(address, size);
}
//================================================================
void AddressList::AddAddress(const uint64_t& byteaddr, const uint64_t& size) {

  //allocate memory for the address vector
  try {
    if ((sequence_no_ % kReserveCount) == 0) address_list_.reserve(kReserveCount);

  } catch (std::bad_alloc& e) {
    std::cerr
        << "error allocating memory for address trace vector, address count"
        << sequence_no_ << std::endl;
    throw;
  }
  uint64_t offset = byteaddr & (CacheParam::Instance()->LineSize() - 1);
  //lineaddress = byteaddr >> CacheParam::Instance()->BitsForLine();
  // this try block is for allocating memory for the address set and the queue it holds
  try {
    // splitter
    uint64_t templinesize = 0;
    do {
      Address temp_addr(byteaddr + templinesize);
      address_list_.push_back(temp_addr);
      address_set_[temp_addr.LineAddress()].push(sequence_no_++);
      templinesize = templinesize + CacheParam::Instance()->LineSize();
    } while (size + offset > templinesize);
  } catch (std::bad_alloc& e) {
    address_list_.pop_back();
    std::cerr
    << "error allocating memory for address trace set, address count"
    << sequence_no_ << std::endl;
    throw;
  }
 }

//======================================================
typedef std::queue<uint64_t> TimeStampQueue;
typedef std::map<uint64_t, TimeStampQueue> AddressSet;
class AddressList {
public:
  AddressList(const char* tracefilename);
  bool Simulate(uint64_t *hit_count, uint64_t* miss_count);
  ~AddressList();

private:
  void AddAddress(const uint64_t& byteaddr, const uint64_t& size);
  void ParseTraceFile(const char* filename);
  void StoreTokens(char* line, uint64_t * const linecount);

  std::vector<Address> address_list_;
  AddressSet address_set_;
  uint64_t sequence_no_;
  CacheMemory cache_;

  AddressList (const AddressList&);
  AddressList& operator=(const AddressList&);
};
void AddressList::ParseTraceFile(const char*filename){
_文件中的std::ifstream;

std::cerr映射在填充时对其输入进行排序,以优化查找时间并提供已排序的输出。听起来好像您没有使用查找功能,因此最佳策略是使用另一种方法对列表进行排序。这对于排序不适合内存的集合非常有用。即使您正在进行查找,也可以使用二进制搜索只要每个记录的大小固定,将其转换为排序文件的速度就会比简单的方法快。

映射在填充时对其输入进行排序,以优化查找时间并提供排序输出。听起来好像您没有使用查找功能,所以最佳策略是使用另一种方法对列表进行排序。对于对不适合内存的集合进行排序。即使您正在进行查找,只要每个记录的大小都是固定的,对已排序文件进行二进制搜索也比简单的方法要快。

因为您的数据集似乎比您的内存大得多,您必须在磁盘上编写索引。可能最容易将整个内容导入一个数据库,让它为你建立索引。

因为你的数据集似乎比你的内存大得多,你必须在磁盘上写一个索引。可能最容易将整个内容导入数据库,让它为你建立索引。

请原谅我说了一些显而易见的事情,但是需要存储和查询大型数据库高效的数据量是数据库发明的确切原因。它们已经以比您或我在合理的时间内所能想到的更好的方式解决了所有这些问题。无需重新发明轮子。

请原谅我说了一些可能显而易见的事情,但需要在数据库中存储和查询大量数据高效的方式是数据库发明的确切原因。它们已经以比你我在合理的时间内所能想到的更好的方式解决了所有这些问题。无需重新发明轮子。

你是在32位还是64位体系结构上这样做的?@Abhi估计存储这么多记录需要多少内存。Th我想知道一个进程在你的特定机器/体系结构上是否可以访问那么多内存。@jdv 64位@Vijay:问题是我不知道记录的数量。它们基本上是程序访问的内存地址。它们会很大。根据程序的不同,在64位系统上,单是1000亿到1万亿左右的指针存储需要8 TB内存。您可能需要重新考虑您的策略。您的平台可能根本不允许分配这么多内存。如果可以,请尝试将文件分块处理。您是在32位还是64位体系结构上执行此操作?@Abhi估计存储这么多记录需要多少内存。然后确定是否一个进程可以在您特定的机器/体系结构上访问那么多内存。@jdv 64位@Vijay:问题是我不知道记录的数量。它们基本上是程序访问的内存地址。它们会很大。取决于程序,1000亿到1万亿左右。单是64位系统上的1万亿指针就需要8个TB的存储内存。您可能需要重新考虑您的策略。您的平台可能根本不允许分配这么多内存。如果可以,请尝试分块处理该文件。非常感谢!这让我忽略了。SQLite解决了这个问题!非常感谢!这让我忽略了。SQLite解决了这个问题!