【问题标题】:Memory errors for Sieve of Eratosthenes that allocates memory on the stack and heap在堆栈和堆上分配内存的 Eratosthenes 筛的内存错误
【发布时间】:2019-09-23 13:20:47
【问题描述】:

我已经实现了以下版本的埃拉托色尼筛法,它在堆上分配内存来存储表示素数的数组。

void sieve(int *primes, int n) {
   for (int i = 0; i < n - 1; i++) {
      primes[i] = 1;
   }

   for (int p = 2; p <= n; p++) {
      if (primes[p - 2] == 1) {
         for (int i = 2*p - 2; i < n; i += p) {
            primes[i] = 0;
         }
      }
   }
}
void print_sieves(int n) {
   if (n < 3) return;

   int *primes = (int*) malloc((n - 1) * sizeof(int));
   sieve(primes, n);
   int print_counter = 0;

   for (int i = 0; i < n - 1; i++) {
      if (primes[i] == 1) {
         printf("%10d ", i + 2);
         print_counter++;

         if (print_counter % COLUMNS == 0)
            printf("\n");
      }
   }
   free(primes);
   printf("\n");
}

对于传递给print_sieves 的大多数参数,程序按预期工作,但是,当将15 传递给print_sieves 时,我最终会出现以下错误:

a.out: malloc.c:2392: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
Aborted (core dumped)

对于这个程序的一个稍微不同的版本,我在堆栈上分配内存来存储表示素数的数组,我遇到了一个不同的错误。也就是说,当试图找到太大的素数时,例如当使用参数10000000 调用print_sieves 时,我遇到了错误Segmentation fault (core dumped)sieve 的实现对于两个版本的程序是相同的,但 print_sieves 有细微的差别。下面是我在堆栈上分配内存的print_sieves 函数的代码:

void print_sieves(int n) {
   if (n < 3) return;

   int primes[n - 1];
   sieve(primes, n);
   int print_counter = 0;

   for (int i = 0; i < n - 1; i++) {
      if (primes[i] == 1) {
         printf("%10d ", i + 2);
         print_counter++;

         if (print_counter % COLUMNS == 0)
            printf("\n");
      }
   }
   printf("\n");
}

我的猜测是我没有正确管理内存,但我不知道我哪里出错了。什么可能导致这些错误以及如何解决?

【问题讨论】:

  • 在这两种变体中,您都为 n - 1 个整数分配空间,同时循环到并包括 n。尝试为 n + 1 分配空间
  • @hager Allocating space for n + 1 ints 解决了第一个错误,即为基于堆的实现调用print_sieves(15) 时出现的错误,但第二个错误仍然存​​在。
  • n ints分配空间也足以解决第一个问题。我想知道为什么为n - 1 ints 分配空间是不够的,因为我在传递参数n 时检查了闭区间[2, n] 中的所有整数,其中只有n - 1
  • 这取决于您运行的平台,在我的 linux 桌面上,默认的最大堆栈大小为 8192 kB。您似乎有相同的限制,因为 2090000 * sizeof(int) 那时几乎不适合堆栈。
  • 这不是您的问题的原因,但是当我们在这里时,我建议您阅读并理解the question on why not to cast the return value of malloc() and family in C。首选int *primes = malloc(sizeof *primes * (n+1));

标签: c memory-management sieve-of-eratosthenes


【解决方案1】:

由于您为n - 1 元素分配内存,我建议将sieve() 中的最内层循环从

         for (int i = 2*p - 2; i < n; i += p) {

         for (int i = 2*p - 2; i < n - 1; i += p) {

为了使索引限制与分配的大小相匹配。

使用n = 10000000,您很可能会遇到堆栈溢出。

您可以使用getrlimit()/setrlimit() 来获取/设置堆栈大小。从最大堆栈大小计算数组大小的限制可能很困难,因为您必须找出除了大数组之外还需要多少堆栈。

另见Increase stack size in Linux with setrlimit

【讨论】:

    猜你喜欢
    • 2011-10-09
    • 2017-01-04
    • 2012-12-05
    • 2011-05-28
    • 2019-05-17
    • 2018-07-24
    • 1970-01-01
    • 2021-11-18
    相关资源
    最近更新 更多