如何主动释放c++程序中STL容器不愿自动释放的内存

readme

STL容器,例如vector, deque, string, map, set等等,是几乎每个c++程序员离不开的工具。STL容器之所以深受c++程序员喜爱,重要原因之一就是它会自动管理内存,不需要程序员手动开辟或释放内存。有利必有弊,STL容器申请的内存不会用完立即释放,通常会保留在内存池中,留给下次复用。某种意义讲这是一种优化,毕竟内存申请释放也是一种消耗,再结合内存碎片等因素,有时甚至是一种不能忽略的消耗。但是对于内存使用敏感的运行环境,STL的这种“优化”行为是不可接受的。这篇博客介绍一种方法主动释放这些STL不愿主动释放的内存希望,可以帮到看到的人。

现状

针对这一问题的思考来自一个项目的调优过程。我们将一个复杂流程采用多线程并发的方式并发处理,恶化了STL内存不释放的问题。客观讲笔者对STL源码了解并不深刻,无法解释多线程与STL内存不释放之间的联系。这里只讨论主要问题。
另外还需要说明一点,我们的程序运行在docker容器中,如果容器内进程占用内存超过阈值,容器管理系统将kill业务进程。如果程序运行于物理机上,猜想当STL开辟内存失败后会被动释放之前保留的内存。
经过一系列调研,发现目前比较流行的方法主要分两种:

  • swap。大致原理是让目标容器与空实例交换。例如下列代码:
vector<string> testVec;
/*其他逻辑*/
vector<string>().swap(testVec);

经过大量测试,发现通过swap释放内存并不可靠。

  • 自己设计并实现STL内存分配器(allocator)和内存释放器(deallocator)。这是很彻底的解决方案,但是保证代码的可移植性和足够高的效率将消耗开发人员大量精力。而且需要比较扎实的STL底层技术积累。

另一种方式

经过一段时间的焦头烂额,我们发现了新的方法,malloc_trim()。
在linux man-pages里面的描述中可以看出,这个api会释放堆中的内存,而且很多时候在free()的时候会自动被调用。看上去和我们的场景十分相似,对STL的使用不需要调用free(),或者说没有机会调用free(),大多数程序员也根本不知道STL容器何时会调用free()。
经过线上试验,发现malloc_trim()也确实解决了内存不释放的问题。接下来我用很简单的程序展现malloc_trim的作用。

测试程序

//common.h
#ifndef _COMMON_H_
#define _COMMON_H_

#include <string>
#include <stdio.h>
#include <memory>
#include <stdlib.h>
#include <unistd.h>
#include <utility>
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>

using namespace std;
#endif
//malloc_trim.cpp
#include "common.h"

int main(void){

    string testStr(1024 * 1024, 'a');
    {
        vector<pair<string, string>> testVec(1024 * 1024);
        for (size_t i = 0; i < 1024 * 1024; ++i)
        {
            testVec.push_back(make_pair(testStr, testStr));
        }
        getchar();
    }

    {
        vector<pair<string, string>> testVec(1024 * 1024);
        for (size_t i = 0; i < 1024 * 1024; ++i)
        {
            testVec.push_back(make_pair(testStr, testStr));
        }
        getchar();
    }

    printf("Have a look at how much memory used.");
    getchar();
    malloc_trim(0);
    printf("How abort now.");
    getchar();

    return 0;
}

编译

g++ -o malloc_trim malloc_trim.cpp -O0 -g -Wall -std=c++11

测试程序说明

在输出“Have a look at how much memory used.”的时候,两个独立作用域中的testVec都已经结束了生命周期,按照c语言的习惯,它们占用的内存应该被释放,但是STL并没有释放。
在输出“How abort now.”的时候,程序占用的内存被释放,达到了目的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值