C++ 맵 지우기 메모리 누수 문제

지도 값은 포인터를 저장합니다.

map에 포함된clear() 함수는 map에 저장된 내용을 모두 지웁니다.그러나 map 값에 포인터가 저장되어 있으면 내부 값이 지워지지 않아 메모리 누수가 발생합니다. 포인터는 반복자를 사용해야 합니다. 비어 있습니다.

값이 포인터인 맵을 삭제 하려면 지우기 반복 삭제를 사용
하십시오. 반복자를 올바르게 사용하십시오. 반복자가 실패하면 프로그램이 충돌합니다.

std::map<int, HHH*> test_map;
HHH* h1 = new HHH;
HHH* h2 = new HHH;
test_map[0] = h1;
test_map[1] = h2;


// 删除
std::map<int, HHH*>::iterator iter;
for (iter = test_map.begin(); iter != test_map.end();)
{
    
    
    delete iter->second;
    iter->second = nullptr;
    // 删除迭代器元素先加加再删,否则迭代器失效程序崩溃!!!(必须iter++不可以++iter)
    test_map.erase(iter++);
}

맵 값은 포인터가 아닌 저장

std::map<int,int> test_map;
test_map[0] = 0;
test_map[1] = 0;

// 删除
test_map.clear(); //值为指针不要这样删除

Clear() 함수를 호출하기 전, Iterator를 통해 값에 있는 포인터의 값을 삭제합니다.

	std::map<int, HHH*> test_map;
    HHH* h1 = new HHH;
    HHH* h2 = new HHH;
    test_map[0] = h1;
    test_map[1] = h2;

    // 删除
    std::map<int, HHH*>::iterator iter;
    for (iter = test_map.begin(); iter != test_map.end();)
    {
    
    
        delete iter->second;
        iter->second = nullptr;
        // 删除迭代器元素先加加再删,否则迭代器失效程序崩溃!!!(必须iter++不可以++iter)
        iter++;
    }
    test_map.clear();

지도에 저장되는 것은 스마트 포인터입니다

스마트포인터를 사용하는 경우 별도로 삭제할 필요가 없으며, 스마트포인터가 자동으로 메모리를 해제해 줍니다.

std::map<int, std::shared_ptr<int>> m_map;
m_map[0] = std::make_shared<int>();
delete m_map[0]; //错误

메모리를 확보하려면 지도를 삭제하세요.

동일한 맵을 여러번 사용해야 할 경우에는 매번 사용 후 반드시 클리어 하시기 바랍니다. 여러번 사용 후 메모리 누수가 발생할 수 있는데 이는 맵 공간이 해제되지 않기 때문이므로 반드시 스왑을 이용하여 클리어 하셔야 합니다.

메모리 오류가 다음과 같이 표시되는 경우:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00000000010ca227 in tcmalloc::SLL_Next(void*) ()
(gdb) bt
#0  0x00000000010ca227 in tcmalloc::SLL_Next(void*) ()
#1  0x00000000010ca2b8 in tcmalloc::SLL_TryPop(void**, void**) ()
#2  0x00000000010ca715 in tcmalloc::ThreadCache::FreeList::TryPop(void**) ()
#3  0x00000000011ebe6c in tc_newarray ()

STL 컨테이너가 clear() 메서드를 호출하면 일반적으로 컨테이너 내부의 모든 객체가 소멸되지만 컨테이너 자체의 메모리는 해제될 수 없습니다. 즉, 바구니에 담긴 물건을 제거하더라도 바구니가 차지한 공간은 그대로 유지되므로, 다음 번에 새로운 물건을 보관할 때 다시 공간을 신청할 필요 없이 용이하게 하기 위함입니다. 즉,clear() 이후 컨테이너의 크기는 0이지만 용량은 변경되지 않습니다. 빈 컨테이너를 swap()하여 컨테이너가 차지하는 용량을 완전히 해제합니다.

#include<map>
#include<vector>
#include<string>
#include <iostream>
#include <time.h>
using namespace std;
 
class useTest
{
    
    
public:
    useTest() {
    
    };
    map<string,string> testMap;
    vector<string> testVertor;
    string id;
};
 
void clearData(map<int, useTest>& needClearMap)
{
    
    
    clock_t  startt = clock();
 
    //分别通过去注释测试下面四种情况
 
    //使用clear
    //needClearMap.clear();
 
    //使用swap
    map<int, useTest> uu;
    needClearMap.swap(uu);
 
    //使用erase
    //needClearMap.erase(needClearMap.begin(), needClearMap.end());
 
    //使用for erase
    //for (auto iter = needClearMap.begin(); iter != needClearMap.end(); iter = needClearMap.erase(iter)) {}
    double sec = double(clock() - startt) / CLOCKS_PER_SEC;
    std::cout << "In Clear Cost Time:" << sec << endl;
}
 
void test()
{
    
    
    map<int, useTest> needClearMap;
    for (size_t i = 0; i <= 10000; ++i)
    {
    
    
        useTest uT;
        for (size_t ii = 0; ii <= 1000; ++ii)
        {
    
    
            uT.testMap[to_string(ii)] = "我是测试,我是测试,我就是测试string";
            uT.testVertor.push_back("我也是测试,我也是测试,我就是测试string");
        }
        uT.id = to_string(i);
        //cout << i << endl;
        needClearMap[i] = uT;
    }
    clock_t  startt = clock();
    clearData(needClearMap);
    double sec = double(clock() - startt) / CLOCKS_PER_SEC;
    std::cout << "clearData Cost Time:" << sec << endl;
}
 
int main()
{
    
    
    for (size_t i = 0; i < 10; ++i)
    {
    
    
        test();
    }
    getchar();
}

특정 맵을 클리어하는 경우 스왑이 가장 효율적이며 시간이 거의 걸리지 않습니다. 하지만 전체 함수를 종료할 때 swap으로 전달된 임시 개체를 해제하는 데 일정 시간이 걸립니다. 지우기 효율은 지우기보다 약간 높습니다. for 루프를 통한 지우기가 더 효율적인 것 같습니다.

map, set 및 unordered_map과 같은 컨테이너의 경우,clear() 또는 swap()을 호출하면 실제로 메모리를 해제할 수 없습니다. 여러 곳에서 언급되었지만, 이 현상(기억이 유지되는 현상)은 정상적인 현상이므로 걱정할 필요가 없습니다. 그러나 다양한 데이터 구조를 저장하는 데 많은 양의 힙 메모리가 사용되면 심각한 메모리 조각화가 발생하고 메모리 누수가 발생합니다.

#include <iostream>
#include <map>
#include <malloc.h>
using namespace std;
void func()
{
    
    
        map<int,string> mp;
        int i = 5000000;
        while(i--)
            mp.insert(make_pair(i,string("hell000o")));
        map<int,string>().swap(mp); //swap
}
int main()
{
    
    
        func();
        cout <<"done."<<endl;
        malloc_trim(0);
        while(1);
}
 

malloc_trim(0);다른 프로세스에서 사용할 수 있도록 운영 체제에 여유 힙 메모리를 반환하는 행을 추가하기만 하면 됩니다 .

추천

출처blog.csdn.net/qq_36314864/article/details/132716800