记一次因为没有关闭 管道导致的内存泄露

news/2024/11/23 5:09:31/

原本想探究一下 string(char*) 是移动构造还是复制构造,在测试时发现了意料之外的内存泄露,
找了挺久没有想到哪里,最后发现是管道没有正确关闭,UNIX 系统中一切皆文件,但是 管道这个文件是待在内存中的,不关闭就会发生内存泄露。
样例代码如下

#include <iostream>
#include <unistd.h>
#include <time.h>
#include <sstream>
#include <vector>#define SEPRATOR '\n'// 原本想探究一下 string(char*) 是移动构造还是复制构造
// 这个函数会导致内存泄露
template <typename... Args> std::string format_string_leak(std::string &&format, Args... elems)
{char *p = new char[1024];sprintf(p, format.c_str(), elems...);return std::string{ p }; // 这里会发生转移吗?实际是不会,这里会发生复制
}// 正确的用法
template <typename... Args> std::string format_string(std::string &&format, Args... elems)
{char *p = new char[1024];sprintf(p, format.c_str(), elems...);std::string ret{ p }; // 这里会发生转移吗?实际是不会,这里会发生复制delete[] p;return ret;
}// 打印资源使用情况,这里只打印内存
void printResource()
{std::string cmd = format_string("ps -p %d -o rss", getpid());FILE *pipe = popen(cmd.c_str(), "r"); // 这里开启了一个管道命令if (!pipe) {std::cerr << "pipline create failed" << std::endl;exit(EXIT_FAILURE);} else {// 通过重复读取的方式将管道文件中的内容读取出来,有没有更简单优雅的方法?std::stringstream ss;char buf[128];while (fgets(buf, sizeof(buf), pipe) != nullptr) {ss << buf;}// 管道输出为该进程的常驻内存占用(kb),要按行解析找到第二行//  RSS// 73893std::vector<std::string> result;std::string token;while (std::getline(ss, token, SEPRATOR)) {result.emplace_back(token);}int mem_usage_kb = std::stoi(result[1]);std::cout << format_string("mem usage : %dkb\n", mem_usage_kb);// 如果这里没有关闭管道,就会发生内存泄露// pclose(pipe); }
}
// 编译 g++ --std=c++11 ./main.cpp -o main
// 模拟泄露 ./main 1000 --leak true
// 正常  ./main 10000
int main(int argc, char *argv[])
{int bench_count = 1;bool leak = false;if (argc >= 2) {bench_count = std::stoi(argv[1]);}if (argc == 4 && std::string(argv[2]) == "--leak") {leak = std::string(argv[3]) == "true" ? true : false;}std::cout << "test leak " << (leak ? "true" : "false") << std::endl;// 重复跑,不断打印内存使用,看是否有上涨for (int i = 0; i < bench_count; i++) {if (leak) {std::string v = format_string_leak("hello world %s, %d, %ld", "yang", 12, 23.L);} else {std::string v = format_string("hello world %s, %d, %ld", "yang", 12, 23.L);}if (i % 20 == 0) {printResource();}}return 0;
}

自己没找出来,是通过 valgrind 工具跑出来的

 valgrind --leak-check=full ./main 1000 --leak false

http://www.ppmy.cn/news/1159865.html

相关文章

性能测试-redis常见问题

缓存击穿、缓存穿透、缓存雪崩 缓存雪崩 解决办法 1.设置缓存失效时间&#xff0c;不要在同一时间 2.redis集群部署 3.不设置缓存设置时间 4.定时刷缓存的时间 缓存穿透 请求不管返回什么数据都返回给redis对参数合法器进行验证&#xff0c;不合法的时候直接过滤掉使用布…

RustDay04------Exercise[01-10]

1.做题须知 这一题告诉我们可以尝试修改下面的输出,在觉得OK之后删除// I AM NOT DONE注释即可进入下一题 // intro1.rs // About this I AM NOT DONE thing: // We sometimes encourage you to keep trying things on a given exercise, even // after you already figured …

基于AT89C52+ADC0809+LCD1602的模数转换实验ptoteus仿真设计

一、仿真原理图&#xff1a; 二、仿真效果图&#xff1a; 三、仿真工程&#xff1a; 基于AT89C52ADC0809LCD1602的模数转换实验ptoteus仿真设计资源-CSDN文库

js实现拖拽功能

基于onMouseDown 、onMouseMove 、onMouseUp 使用 mousedown、mousemove 和 mouseup 事件来实现拖拽的基本思路是&#xff1a; 在 mousedown 事件中&#xff0c;开始追踪拖拽操作并记录鼠标按下的位置。 在 mousemove 事件中&#xff0c;根据鼠标的移动&#xff0c;更新被拖拽…

在C++和Python的项目中使用ROS

如果搜索如何使用ROS&#xff0c;搜索结果肯定是先建立工作空间&#xff0c;在创建功能包等等步骤&#xff0c;但其实不需要这么麻烦。 在Python中使用ROS&#xff0c;只需要在Pycharm的Project Structure中的Add Content Root加入ros的packages就可以了&#xff0c;如下图 在…

数据结构之手撕链表(讲解➕源代码)

0.引言 我们在学习过顺序表之后&#xff0c;会发现两点不是很优秀的操作&#xff1a; 1.顺序表的头插和中间的插入&#xff1a; 非常麻烦&#xff0c;需要不断的覆盖数据。 2.动态开辟空间&#xff1a; a.一般动态开辟的空间都是以2倍的形式开辟&#xff0c;当…

网格大师如何把b3dm转为osgb格式?

答&#xff1a;在网格大师的倾斜数据处理工具中选中“3DTiles转OSGB”&#xff0c;设定数据输入路径和输出路径提交任务即可。 网格大师是一款能够解决实景三维模型空间参考、原点、瓦块大小不统一&#xff0c;重叠区域处理问题的工具“百宝箱”&#xff0c;集格式转换、坐标转…

SpringBootCMS漏洞复现分析

SpringBootCMS&#xff0c;极速开发&#xff0c;动态添加字段&#xff0c;自定义标签&#xff0c;动态创建数据库表并crud数据&#xff0c;数据库备份、还原&#xff0c;动态添加站点(多站点功能)&#xff0c;一键生成模板代码&#xff0c;让您轻松打造自己的独立网站&#xff…