`
byytj
  • 浏览: 48667 次
  • 来自: ...
文章分类
社区版块
存档分类
最新评论

cccccccccc

 
阅读更多

http://blog.csdn.net/gamecreating/article/details/7698719

 

http://blog.csdn.net/zunceng/article/details/7742788 

 

析构过程中内存相关错误的绝大多数原因

今天记录一下长久以来屡次犯的错,每次都是换一种方法编码来绕过这个问题实现功能的,因为这个问题太过隐蔽,导致今天才发现其中真正的原因...下面进行问题描述:

1std::map<std::string, Value> keyValue; // 在函数内部分配的堆栈对象(局部变量)
2ReadData(keyValue);// 从dll中导出的函数
3keyValue.clear(); // delete中出现assert异常


第一行是在应用程序中的堆栈中分配的内存空间。
第二行是我自己写的dll库,用来读取一些数据加入到keyValue中。
第三行是清空keyValue,其实如果不写这一行的话,keyValue也会在函数结尾时清空,到那时同样会出现错误。
这一切乍一看没啥问题,keyValue是局部变量,为什么局部变量的释放会出现异常错误呢?这是因为第二行ReadData的缘故。ReadData的逻辑在另外一个可执行模块中,在其中分配的内存空间不一定与当前模块在同一个堆区。
我们知道,std::map是一个树结构的容器,我在ReadData内部往keyValue中添加了数据,keyValue中会在堆区中分配树节点,而这个节点将会在当前模块在keyValue的析构中被释放。也就是说,我无意中在dll模块中分配了堆空间,又无意中在exe模块中企图释放该空间,这样的行为导致错误是不足为怪的。
时刻牢记,在一个模块中分配和释放同一块内存区域,警惕你所看不见的内存分配和释放。

 

概要

本文比较各种内存分配器(Allocator)在用于STL容器上的性能。参与本次比较的Allocator有:

选择的STL容器为map。其他容器如std::list, std::set, std::multi_set, std::multi_map类似1

对比程序

测试方法 - 对比以下四种情况:

  1. 使用标准的std::map<int, int>。
  2. 使用ScopeAlloc作为分配器。即std::Map<int, int>。
  3. 使用AutoFreeAlloc作为分配器。即std::Map<int, int, std::less<int>, std::AutoFreeAlloc>。
  4. 使用ScopeAlloc作为分配器,且共享同一个std::BlockPool。

测试程序(参见<stdext/Map.h>):

template <class LogT>
class TestMap : public TestCase
{
    WINX_TEST_SUITE(TestMap);
        WINX_TEST(testCompare);
    WINX_TEST_SUITE_END();
 
public:
    enum { N = 20000 };
 
    void doStlMap(LogT& log)
    {
        typedef std::map<int, int> MapT;
        log.print("===== std::map =====\n");
        std::PerformanceCounter counter;
        {
            MapT coll;
            for (int i = 0; i < N; ++i)
                coll.insert(MapT::value_type(i, i));
        }
        counter.trace(log);
    }
 
    void doMap1(LogT& log)
    {
        typedef std::Map<int, int, std::less<int>, std::AutoFreeAlloc> MapT;
        log.print("===== std::Map (AutoFreeAlloc) =====\n");
        std::PerformanceCounter counter;
        {
            std::AutoFreeAlloc alloc;
            MapT coll(alloc);
            for (int i = 0; i < N; ++i)
                coll.insert(MapT::value_type(i, i));
        }
        counter.trace(log);
    }
 
    void doMap2(LogT& log)
    {
        typedef std::Map<int, int> MapT;
        log.print("===== std::Map (ScopeAlloc) =====\n");
        std::PerformanceCounter counter;
        {
            std::BlockPool recycle;
            std::ScopeAlloc alloc(recycle);
            MapT coll(alloc);
            for (int i = 0; i < N; ++i)
                coll.insert(MapT::value_type(i, i));
        }
        counter.trace(log);
    }
 
    void doShareAllocMap(LogT& log)
    {
        typedef std::Map<int, int> MapT;
        std::BlockPool recycle;
        log.newline();
        for (int i = 0; i < 5; ++i)
        {
            log.print("===== doShareAllocMap =====\n");
            std::PerformanceCounter counter;
            {
                std::ScopeAlloc alloc(recycle);
                MapT coll(alloc);
                for (int i = 0; i < N; ++i)
                    coll.insert(MapT::value_type(i, i));
            }
            counter.trace(log);
        }
    }
 
    void testCompare(LogT& log)
    {
        for (int i = 0; i < 5; ++i)
        {
            log.newline();
            doStlMap(log);
            doMap2(log);
            doMap1(log);
        }
        doShareAllocMap(log);
    }
};

测试结果

===== std::map =====
---> Elapse 29649998 ticks (8283.18 ms) (0.14 min) ...
===== std::Map (ScopeAlloc) =====
---> Elapse 9045729 ticks (2527.06 ms) (0.04 min) ...
===== std::Map (AutoFreeAlloc) =====
---> Elapse 9683232 ticks (2705.16 ms) (0.05 min) ...

===== std::map =====
---> Elapse 38099194 ticks (10643.59 ms) (0.18 min) ...
===== std::Map (ScopeAlloc) =====
---> Elapse 15013312 ticks (4194.20 ms) (0.07 min) ...
===== std::Map (AutoFreeAlloc) =====
---> Elapse 15039592 ticks (4201.54 ms) (0.07 min) ...

===== std::map =====
---> Elapse 24698608 ticks (6899.93 ms) (0.11 min) ...
===== std::Map (ScopeAlloc) =====
---> Elapse 10867094 ticks (3035.89 ms) (0.05 min) ...
===== std::Map (AutoFreeAlloc) =====
---> Elapse 15611309 ticks (4361.26 ms) (0.07 min) ...

===== std::map =====
---> Elapse 37594376 ticks (10502.56 ms) (0.18 min) ...
===== std::Map (ScopeAlloc) =====
---> Elapse 8846240 ticks (2471.33 ms) (0.04 min) ...
===== std::Map (AutoFreeAlloc) =====
---> Elapse 8667671 ticks (2421.44 ms) (0.04 min) ...

===== std::map =====
---> Elapse 30175306 ticks (8429.93 ms) (0.14 min) ...
===== std::Map (ScopeAlloc) =====
---> Elapse 9033720 ticks (2523.71 ms) (0.04 min) ...
===== std::Map (AutoFreeAlloc) =====
---> Elapse 8723023 ticks (2436.91 ms) (0.04 min) ...

===== doShareAllocMap =====
---> Elapse 8441194 ticks (2358.18 ms) (0.04 min) ...
===== doShareAllocMap =====
---> Elapse 7651772 ticks (2137.64 ms) (0.04 min) ...
===== doShareAllocMap =====
---> Elapse 7900730 ticks (2207.19 ms) (0.04 min) ...
===== doShareAllocMap =====
---> Elapse 7861035 ticks (2196.10 ms) (0.04 min) ...
===== doShareAllocMap =====
---> Elapse 7530844 ticks (2103.86 ms) (0.04 min) ...

测试结论

使用ScopeAlloc或者AutoFreeAlloc后,STL容器的性能有显著提高。而ScopeAlloc与AutoFreeAlloc在该容器存在大量内存分配时区别不显著2。另外,由于内存池技术的作用,ScopeAlloc在Share同一个BlockPool后,性能略有改善。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics