免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 10058 | 回复: 21
打印 上一主题 下一主题

[C++] c++ allocator 内存释放问题,急 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-08-14 22:57 |只看该作者 |倒序浏览
20可用积分
本帖最后由 HJLin 于 2010-12-14 14:53 编辑

最近程序中使用了大量的string,发现了内存不能释放的问题。试了很多方法,包括new vector,swap vector等等均没有作用。除了代码中注释的部分有时会正确释放内存之外(在内存占用不多的情况下100M到1、2G都没有问题,但是到20G的时候又不行了,32G内存的机器。)
强烈郁闷中,已经纠缠我一个月之久了。请求高手解惑:<
上代码:

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>

  4. using namespace std;
  5. [code]
  6. sdf
复制代码
void fun()
{
        const int size = 5000000;
        vector<string> coll;
        coll.reserve(size);

        for (int i=0; i<size; i++)
        {
                coll.push_back("abc");
        }

        return;
}

int main()
{
        fun();

        cout << "------------------" << endl;

        getchar();
        /*
        char *p = new char[100*1000];
        delete[] p;
        */
        sleep(100);
        return 0;
}
[/code]
机器:linux as4u4-32 as4u4-64 2.6.9
现象:
在main函数中,fun执行结束之后,有117M左右的内存没有释放。
分析:
fun中,coll在堆中占用的内存是 4B * 5000000 = 17M 左右 (通过mmap系统调用分配,在高地址)
string在堆中的所有内存是 (4*4 + 3对齐8字节) 24B * 5000000 = 117M 左右 (brk系统调用分配,在低地址),正是这个117M的内存没有归还给系统,可能因为string的分配器std::allocator 的原因没有调用delete释放资源,std::allocator默认使用的__gnu_cxx::new_allocator。查看了代码发现没有什么特殊之处。
引用c++标准程序库中一句话:
缺省配置器会执行内存分配和回收的一般性手法,也就是呼叫new和delete操作符。但是c++并没有对于在什么时候以什么方式调用这些操作符给与明确规定。

没有查到更多的资料了,希望高手出手拉小弟一把。感激涕零。。。
regards

qq:110024218
e-mail:linhanjie123@163.com

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
2 [报告]
发表于 2009-08-14 23:05 |只看该作者

回复 #1 HJLin 的帖子

crt有可能不会归还给OS, 而是标记为“unused”, 用于下一次分配。

可以试试:
int main() {
        for (int i=0;i<12;++i) fun();
}

看看是否依然是117M, 还是117M × 12。

论坛徽章:
0
3 [报告]
发表于 2009-08-14 23:10 |只看该作者

回复 #2 OwnWaterloo 的帖子

谢谢,这个我知道!这段资源确实可以继续使用,还是117M。但是我想找到一个办法,释放这个空间的办法。还有c++到底怎么实现的,查不到什么资料了。
实际上我的程序有20G的小内存没有释放,上面的只是个测试。所以我想找到释放的办法。谢谢

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
4 [报告]
发表于 2009-08-14 23:23 |只看该作者

回复 #3 HJLin 的帖子

原帖由 HJLin 于 2009-8-14 23:10 发表
引用c++标准程序库中一句话:
缺省配置器会执行内存分配和回收的一般性手法,也就是呼叫new和delete操作符。但是c++并没有对于在什么时候以什么方式调用这些操作符给与明确规定。


这句话的出处是在哪?


原帖由 HJLin 于 2009-8-14 23:10 发表
包括new vector,swap vector等等均没有作用。


这些手法, 解决的问题有点类似。

当vector的容量减小的时候, vector是否应该释放多余的空间?
我不记得C++标准是否有这个要求了。
但new vector, swap vector是一种可以保证”vector只保留需要空间“的手法。

当vector释放掉空间的时候,又会继续遇见这样类似的问题。
这空间到底是真正归还, 还是不归还, 留作下次使用?

这个。。。 至少在我的印象中, C和C++标准都没有提供这样机制, 将crt不使用的内存归还给OS。
lz可以查一下你使用的STL和crt, 比如libstdc, libstdc++ ,看看有没有提供这样的函数。

比如Windows下有SetProcessWorkingSetSize, 但这个函数其实不是那么好用的……



而且:
原帖由 HJLin 于 2009-8-14 23:10 发表
这段资源确实可以继续使用,还是117M。


如果真想lz所说, 117M没有泄露, 难道20G是lz的程序内存使用峰值???
如果20G真是峰值,  那lz你还是不要找真正归还的函数了……
从改进程序, 减少内存使用峰值方面考虑一下吧。

论坛徽章:
0
5 [报告]
发表于 2009-08-14 23:31 |只看该作者

回复 #4 OwnWaterloo 的帖子

缺省配置器会执行内存分配和回收的一般性手法,也就是呼叫new和delete操作符。但是c++并没有对于在什么时候以什么方式调用这些操作符给与明确规定。

这句话的位置, stl标准程序库,32页 733页也说道点。

但是都是点到即止,不知道到从哪可以找到c++的new和delete的具体实现源码,说不定可以找到问题和解决。

如果20G真是峰值,  那lz你还是不要找真正归还的函数了……
从改进程序, 减少内存使用峰值方面考虑一下吧。

我想发现了问题,最好能够找到它的原因所在,而不是避而不见。c++应该是可以解决这个问题的,可能我不知道

论坛徽章:
0
6 [报告]
发表于 2009-08-14 23:51 |只看该作者
按我的理解, LZ所提的种种分配内存的方法应该都是在堆上分配的.
在linux内核中, 堆是一个一端固定, 一端可伸缩的内存区间.
堆空间的申请很方便, 移动可伸缩的那一端, 使区间增加就可以了. 但是释放堆的空间就不是减小区间这么简单. 因为可能堆的这一端附近有一小块内存没被释放, 门户被卡住了, 堆没办法减小.
所以, 使用堆的空间是有个原则, 就是"就近释放". 越晚释放的空间要越早申请, 越早释放的空间, 越晚申请.

一般情况下, 这方面并不是很需要讲究. 对于内存匮乏的嵌入式系统和内存消耗很大的大型系统, 这方面可能还是需要注意一下的.

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
7 [报告]
发表于 2009-08-14 23:55 |只看该作者

回复 #5 HJLin 的帖子

我找到那句话了。

对allocator来说, 确实标准没有规定它调用operator new, operator delete, 或者是其他分配函数的时机。
但是, 当vector和string 被析构的时候, 标准是有规定的, 必须调用 get_allocator().deallocate.


对问题“将不使用的内存归还”, C++确实可以解决。 也许会复杂到你接受不了。
关键是, 解决了这个问题, 能将不使用的内存归, 那又怎样?
内存依然会继续被需求, 然后分配出来。


你也测过了, fun反复调用, 117M的内存使用不会继续升高, 这就说明你使用的stl,crt都没泄露。
那为什么会用到2G ?  要么就是你程序其他地方泄露, 要么就是峰值确实太高。

原帖由 HJLin 于 2009-8-14 23:31 发表
不是避而不见

那就不要老以为库出了毛病, 先从减少内存使用峰值, 甚至检查程序中的内存泄露入手。

论坛徽章:
0
8 [报告]
发表于 2009-08-14 23:57 |只看该作者

回复 #6 kouu 的帖子

谢谢,这个我知道,堆是内核管理进程的特殊一个线性区。为了这问题,我差不多看了一遍深入理解linux内核的内存管理部分。
而且这个低端的地址确实已经释放了,可以gdb调试打印等。我的注释掉的代码,new delete 能够成功释放内存说明了这点。
问题还是c++不知道动了什么手脚,找不到相关资料了啊,急啊

论坛徽章:
0
9 [报告]
发表于 2009-08-15 00:09 |只看该作者

回复 #7 OwnWaterloo 的帖子

这个是测试程序了,实际程序的话耗费的资源远超这么多!减少峰值的话确实可以办到,但是现在发现了问题。不仅仅是为了解决问题而解决问题。
程序中注释掉的部分,new char[] 然后delete 有可能会把资源释放掉,我是比较想弄清底层运作的人了,所以才斗胆求助的咯。

论坛徽章:
0
10 [报告]
发表于 2009-08-15 00:22 |只看该作者
这个问题... 进程占着很大的空间, 排除内存泄漏, 那么就是说应用程序已经把内存归还给lib了, 但是lib没有将归还内核.

lib为什么不归还内核? 我不太相信一个成熟的lib会占着很大的内存, 能够释放而不释放. 所以, 只有一个解释, lib没法释放. 为什么? 就是因为后申请的内存没有释放!
后申请的内存未释放不是lib能够管得了的, 所以, 最终还是得看看自己的程序呀~
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP