内存错误低于在C++年实现埃拉托色尼筛分时的预期
Memory error at lower limit than expected when implementing Sieve of Eratosthenes in C++
我的问题与这里描述的问题有关。我写了一个埃拉托色尼筛的C++实现,如果我将目标值设置得太高,它就会出现内存溢出。正如该问题中所建议的,我能够通过使用布尔<vector>
而不是普通数组来解决问题。
但是,我以比预期低得多的值击中内存溢出,大约n = 1 200 000
.上面链接的线程中的讨论表明,正常的C++布尔数组为每个条目使用一个字节,因此使用 2 GB 的 RAM,我希望能够到达n = 2 000 000 000
量级的某个地方。为什么实际内存限制要小得多?
为什么使用<vector>
将布尔值编码为位而不是字节,可计算极限增加了八倍以上?
这是我的代码的一个工作示例,n
设置为一个小值。
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
int main() {
// Count and sum of primes below target
const int target = 100000;
// Code I want to use:
bool is_idx_prime[target];
for (unsigned int i = 0; i < target; i++) {
// initialize by assuming prime
is_idx_prime[i] = true;
}
// But doesn't work for target larger than ~1200000
// Have to use this instead
// vector <bool> is_idx_prime(target, true);
for (unsigned int i = 2; i < sqrt(target); i++) {
// All multiples of i * i are nonprime
// If i itself is nonprime, no need to check
if (is_idx_prime[i]) {
for (int j = i; i * j < target; j++) {
is_idx_prime[i * j] = 0;
}
}
}
// 0 and 1 are nonprime by definition
is_idx_prime[0] = 0; is_idx_prime[1] = 0;
unsigned long long int total = 0;
unsigned int count = 0;
for (int i = 0; i < target; i++) {
// cout << "n" << i << ": " << is_idx_prime[i];
if (is_idx_prime[i]) {
total += i;
count++;
}
}
cout << "nCount: " << count;
cout << "nTotal: " << total;
return 0;
}
输出
Count: 9592
Total: 454396537
C:Users[...].exe (process 1004) exited with code 0.
Press any key to close this window . . .
或者,改变n = 1 200 000
收益率
C:Users[...].exe (process 3144) exited with code -1073741571.
Press any key to close this window . . .
我在Windows上使用Microsoft Visual Studio解释器
,默认设置。将注释转换为完整答案:
操作系统在内存中保留一个特殊部分来表示程序的调用堆栈。每个函数调用都会将一个新的堆栈帧推送到堆栈上。如果函数返回,则会从堆栈中删除堆栈帧。堆栈帧包括函数参数的内存和函数的局部变量。剩余的内存称为堆。在堆上,可以进行任意内存分配,而堆栈的结构由程序的控制流控制。为堆栈保留的内存量有限,当堆栈已满时(例如,由于嵌套函数调用过多或本地对象太大(,会出现堆栈溢出。因此,应在堆上分配大型对象。
关于堆栈/堆的一般参考:链接、链接
要在堆上分配内存(C++(,您可以:
-
使用
vector<bool> is_idx_prime(target);
,它在内部执行堆分配,并在向量超出范围时为您解除分配内存。这是最方便的方法。 -
使用智能指针管理分配:
auto is_idx_prime = std::make_unique<bool[]>(target);
当数组超出范围时,这也将自动释放内存。 -
手动分配内存。我提到这一点只是出于教育目的。正如保罗在评论中提到的,通常不建议手动分配内存,因为您必须再次手动释放内存。如果你有一个具有许多内存分配的大型程序,则不可避免地会忘记释放一些分配,从而产生内存泄漏。当您有一个长时间运行的程序(例如系统服务(时,创建重复的内存泄漏最终会填满整个内存(从个人经验来看,这在实践中绝对会发生(。但从理论上讲,如果要进行手动内存分配,您将使用
bool *is_idx_prime = new bool[target];
然后使用delete [] is_idx_prime
再次释放。
- 内存错误低于在C++年实现埃拉托色尼筛分时的预期
- 列出埃拉托色尼的筛子
- 埃拉托色尼的筛子在一段上
- 筛子的埃拉托色尼错误实现
- 为什么我的埃拉托色尼代码筛子无限循环.我已经用几个数字进行了测试
- 埃拉托色尼筛子算法的效率
- 埃拉托色尼的筛子和哥德巴赫猜想
- 如何使用埃拉托斯特内斯筛算法改进素数程序
- 优化埃拉托色尼筛
- 使用地图的埃拉托色尼筛子进行记忆和素数生成
- 需要帮助在 c++ 中优化埃拉托色尼筛
- 埃拉托色尼筛,用于大数 c++
- 埃拉托色尼筛C++
- 使用二维阵列用C++求解埃拉托色尼筛
- 埃拉托申斯孢子虫Prime1 C++的分段筛
- 埃拉托斯梯尼的筛子,数组太大,以至于内存越界
- 分割如何提高埃拉托斯尼筛的运行时间
- 并行化埃拉托色尼筛 用于查找素数的算法
- 运行时错误 (SIGSEGV) SPOJ 筛子的埃拉托色尼
- 当m和n在10^10范围内相当大时,使用埃拉托色尼筛法打印m和n之间的素数