【问题标题】:Segmentation fault while reading a large array from a file. C++/gcc从文件中读取大型数组时出现分段错误。 C++/GCC
【发布时间】:2014-10-16 14:17:57
【问题描述】:

在下面的代码中,我试图找到 fileA 中第二列具有相同值的行的频率。 (每行有两列,都是整数。)fileA的样本:

1   22
8   3
9   3

我必须像这样在 fileB 中写入输出:

22   1
3    2

因为元素 22 在第二列中重复了一次(并且 3 重复了 2 次。)

fileA 非常大(30G)。其中有 41,000,000 个元素(换句话说,fileB 有 41,000,000 行)。这是我写的代码:

void function(){

unsigned long int size = 41000000;
int* inDeg = new int[size];

for(int i=0 ; i<size; i++)
{
    inDeg[i] = 0;
}


ifstream input;
input.open("/home/fileA");

ofstream output;
output.open("/home/fileB");

int a,b;
    
while(!input.eof())
{
   input>>a>>b; 
   inDeg[b]++; //<------getting error here.
}
input.close();


for(int i=0 ; i<size; i++)
{
    output<<i<<"\t"<<inDeg[i]<<endl;
}

output.close();
delete[] inDeg;

}

我在 while 循环的第二行遇到分段错误错误。第 547387 次迭代。我已经根据this给栈内存分配了600M。我正在使用 gcc 4.8.2(在 Mint17 x86_64 上)。


已解决

我彻底分析了fileA。 hyde 提到的问题的原因与硬件无关。 Segfault 原因是索引错误。将大小更改为 61,500,000 解决了我的问题。

【问题讨论】:

  • 数组索引从 0 开始,而不是 1。inDeg[size] 不指向您分配的内存。 eof() 设置在您阅读之后,而不是之前。你在错误的地方检查它。
  • 文件中b值没有0元素,都小于41000000吧?
  • 当崩溃发生时b 是什么?
  • Cameron: 数组的索引不是这里的情况。我用正确的索引重写了代码。仍然是同样的问题。 @crashmstr:实际上我的代码中大小的实际值是:40171637。在错误时 b=40172544
  • while(!input.eof())这是错误的stackoverflow.com/questions/5605125/…

标签: c++ gcc segmentation-fault


【解决方案1】:

在声明中:

while(!input.eof())
{
   input>>a>>b; 
   inDeg[b]++;
}

b 是数组的索引吗?

当您读取值时:
1 22 您将丢弃 1 并增加数组中插槽 22 处的值。

在增加inDeg[b] 的值之前,您应该检查b 的范围:

  while (input >> a >> b)
  {
    if ((b >= 0) && (b < size))
    {
      int c = inDeg[b];
      ++c;
      inDeg[b] = c;
    }
    else
    {
      std::cerr << "Index out of range: " << b << "\n";
    }
  }

【讨论】:

    【解决方案2】:

    您在堆中分配了一个太大的数组。这是一个内存问题,你的堆不能占用那么多空间。

    您应该将输入和输出分成更小的部分,因此例如创建一个 for 循环,每次 100k 执行一次,删除它们,然后执行下一个 100k。

    在这种情况下尝试异常处理,这是一个示例 sn-p 如何管理对太大数组的异常检查:

      int ii;
    
       double *ptr[5000000];
    
    
    
       try
    
       {
    
          for( ii=0; ii < 5000000; ii++)
    
          {
    
             ptr[ii] = new double[5000000];
    
          }
    
       }
    
       catch ( bad_alloc &memmoryAllocationException )
    
       {
    
          cout << "Error on loop number: " << ii << endl;
    
          cout << "Memory allocation exception occurred: "
    
               << memmoryAllocationException.what()
    
               << endl;
    
       }
    
       catch(...)
    
       }
    
          cout << "Unrecognized exception" << endl;
    
       {
    

    【讨论】:

    • 如果它不适合堆,是什么让您认为它更容易适合数据部分?无论如何,它只有~156MB,在堆上分配不应该有任何问题。如果有,new 会抛出 std::bad_alloc
    • 当我使用 int inDeg[size];我在第一个 for 循环开始时遇到分段错误错误。
    • @Cameron 我说试试看,我不确定它是大于还是小于堆,但感谢您提供的信息,很高兴知道。你知道堆有多大主要取决于什么吗?我会更新我的答案。
    • 您是建议将其设为全局变量(不好)还是将其分配在 stack 中(比堆smaller 几个数量级) ?s
    • ~160MB 分配应该没什么大不了的,顺便说一句。此外,将其全部设置为 0 不会崩溃,因此显然分配很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-14
    • 2022-10-04
    • 2019-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多