在C++程序开发中,合理限制内存使用上限能够避免程序异常占用过多系统资源,提升整体运行的稳定性。无论是服务端程序还是嵌入式场景下的应用,精准控制内存都是资源管理的核心需求之一。

系统层面限制:使用setrlimit函数
在类Unix系统中,可以通过setrlimit系统调用设置进程的资源限制,其中RLIMIT_AS参数可以限制进程的最大虚拟内存使用量,这是最直接限制程序内存上限的方式。
该方式的作用范围是整个进程,不需要修改程序的内存申请逻辑,适合快速为已有程序添加内存限制。
代码示例
#include <sys/resource.h>
#include <iostream>
#include <cstdlib>
int main() {
// 定义资源限制结构体
struct rlimit mem_limit;
// 设置最大虚拟内存为100MB,单位字节
mem_limit.rlim_cur = 100 * 1024 * 1024;
mem_limit.rlim_max = 100 * 1024 * 1024;
// 设置RLIMIT_AS限制,如果失败输出错误信息
if (setrlimit(RLIMIT_AS, &mem_limit) != 0) {
std::cerr << "设置内存限制失败" << std::endl;
return 1;
}
// 尝试申请超过限制的内存,会触发bad_alloc异常
try {
// 申请200MB内存,超过设置的100MB限制
char* big_mem = new char[200 * 1024 * 1024];
delete[] big_mem;
} catch (const std::bad_alloc& e) {
std::cerr << "内存申请失败,超过限制: " << e.what() << std::endl;
}
return 0;
}
注意事项
RLIMIT_AS限制的是虚拟内存总量,包含堆、栈、共享内存等所有虚拟地址空间的使用- 设置的限制对该进程以及后续创建的子进程都生效
- Windows系统没有
setrlimit接口,需要使用Windows API的SetProcessWorkingSetSize或者作业对象(Job Object)实现类似功能
代码层面限制:自定义内存分配器
如果需要在更细的粒度上控制内存使用,比如只限制某个模块或者某类对象的内存申请,可以自定义内存分配器,在申请内存时校验当前已使用内存是否超过上限。
实现思路
自定义分配器需要重载operator new和operator delete,维护一个全局的内存使用计数器,每次申请内存时累加计数器,释放时减少计数器,当申请的内存会导致计数器超过上限时抛出异常。
代码示例
#include <iostream>
#include <cstdlib>
#include <mutex>
// 全局内存使用计数器,单位字节
static size_t g_used_memory = 0;
// 内存上限,设置为50MB
static const size_t MEMORY_LIMIT = 50 * 1024 * 1024;
// 互斥锁保证多线程下计数器操作安全
static std::mutex g_mem_mutex;
// 重载全局operator new
void* operator new(size_t size) {
std::lock_guard<std::mutex> lock(g_mem_mutex);
// 检查申请后的总内存是否超过上限
if (g_used_memory + size > MEMORY_LIMIT) {
throw std::bad_alloc();
}
// 申请内存
void* ptr = malloc(size);
if (!ptr) {
throw std::bad_alloc();
}
// 更新计数器
g_used_memory += size;
return ptr;
}
// 重载全局operator delete
void operator delete(void* ptr, size_t size) noexcept {
if (!ptr) return;
std::lock_guard<std::mutex> lock(g_mem_mutex);
free(ptr);
// 更新计数器
g_used_memory -= size;
}
int main() {
try {
// 第一次申请30MB内存
char* mem1 = new char[30 * 1024 * 1024];
std::cout << "第一次申请内存成功" << std::endl;
// 第二次申请30MB内存,总使用60MB超过50MB上限
char* mem2 = new char[30 * 1024 * 1024];
delete[] mem2;
delete[] mem1;
} catch (const std::bad_alloc& e) {
std::cerr << "内存申请失败,超过自定义上限: " << e.what() << std::endl;
}
return 0;
}
注意事项
- 该方式只拦截通过
new申请的内存,如果是用malloc或者第三方库的内存申请接口,需要额外适配 - 多线程场景下必须使用互斥锁保证计数器操作的原子性,避免计数错误
- 如果程序中存在内存泄漏,计数器只会递增不会递减,会提前触发限制
两种方式的对比
可以根据实际场景选择合适的内存限制方式,以下是两种方式的特性对比:
| 限制方式 | 作用范围 | 实现难度 | 跨平台性 | 粒度控制 |
|---|---|---|---|---|
| setrlimit系统调用 | 整个进程 | 低 | 类Unix系统原生支持 | 粗粒度 |
| 自定义内存分配器 | 可自定义范围 | 中 | 可跨平台实现 | 细粒度 |
补充:内存使用监控
除了直接限制内存上限,还可以在程序中定期监控内存使用情况,当接近上限时主动释放非必要资源或者输出告警日志,这种方式相对柔性,不会直接终止内存申请操作。
可以通过读取/proc/self/status文件(类Unix系统)或者调用系统API获取当前进程的内存使用量,再和预设的阈值做对比。
#include <iostream>
#include <fstream>
#include <string>
// 获取当前进程虚拟内存使用量,单位KB
size_t get_vm_usage() {
std::ifstream status_file("/proc/self/status");
std::string line;
while (std::getline(status_file, line)) {
if (line.find("VmSize:") == 0) {
// 格式为 VmSize: 12345 kB
size_t pos = line.find_first_of("0123456789");
if (pos != std::string::npos) {
return std::stoi(line.substr(pos));
}
}
}
return 0;
}
int main() {
size_t vm_usage = get_vm_usage();
std::cout << "当前进程虚拟内存使用量: " << vm_usage << " KB" << std::endl;
// 假设阈值为102400KB(100MB),超过则输出告警
if (vm_usage > 102400) {
std::cerr << "内存使用接近上限,请注意释放资源" << std::endl;
}
return 0;
}
C++memory_limitresource_controlsetrlimit修改时间:2026-07-20 19:33:16