• 关于类静态成员变量指针通过动态分配的内存怎样回收的探讨


    一个类假如存在一个静态成员变量指针,在下面几种情况下动态分配内存。该怎样回收内存:

    1)在外部函数中动态分配内存,代码例如以下:

    test.cpp

    class Test
    {
    public:
        static char* m_pSZ;
    };
    
    char* Test::m_pSZ = NULL;
    
    void testAlloc()
    {
        Test::m_pSZ = new char[16];
    }
    
    int main()
    {
        testAlloc();
        
        
        std::cout << "Already alloc for Test::m_pSZ!" << std::endl;
    
        return 0;
    }

    通过使用g++ -g test.cpp -c test编译。再g++ -o test test.o链接成运行文件。最后通过检測内存泄漏工具valgrind检測。命令例如以下:

    valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./test

    检測结果例如以下:

    ==14924== Memcheck, a memory error detector
    ==14924== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
    ==14924== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
    ==14924== Command: ./test
    ==14924== 
    Already alloc for Test::m_pSZ!
    ==14924== 
    ==14924== HEAP SUMMARY:
    ==14924==     in use at exit: 16 bytes in 1 blocks
    ==14924==   total heap usage: 1 allocs, 0 frees, 16 bytes allocated
    ==14924== 
    ==14924== 16 bytes in 1 blocks are still reachable in loss record 1 of 1
    ==14924==    at 0x402ACDB: operator new[](unsigned int) (vg_replace_malloc.c:383)
    ==14924==    by 0x80486EE: testAlloc() (test.cpp:13)
    ==14924==    by 0x8048703: main (test.cpp:18)
    ==14924== 
    ==14924== LEAK SUMMARY:
    ==14924==    definitely lost: 0 bytes in 0 blocks
    ==14924==    indirectly lost: 0 bytes in 0 blocks
    ==14924==      possibly lost: 0 bytes in 0 blocks
    ==14924==    still reachable: 16 bytes in 1 blocks
    ==14924==         suppressed: 0 bytes in 0 blocks
    ==14924== 
    ==14924== For counts of detected and suppressed errors, rerun with: -v
    ==14924== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

    从上面结果看。还是有泄露的。泄露类型属于"still reachable",对于这类型泄露,在网上查了下:

    内存泄露能够分为两种:
    一种是。程序中有指针指向通过malloc或者new申请的内存。可是在程序结束前,一直未收回。

    假设这样的内存一直添加的话,可能导致内存耗尽。

    只是程序结束后系统会自己主动回收这些内存。


    还有一种是,通过malloc或者new申请的内存,可是程序中已经没有指针指向申请的内存。

    程序一直在运行。泄露的内存会越来越多,可能会耗尽程序的堆内存。

    对于上述的第一种内存泄露的情况。在valgrind的报告中会表示为“still reachable”。
    对于另外一种情况的内存泄露,在valgrind的报告中会表示为”Directly lost和Indirectly lost”
    另外对于valgrind报告中的“possibly lost”,是由于指针没有指向到申请堆的開始。如,c++的string有内存池的概念。

    假设程序中使用了string,且非正常退出(如使用ctrl+c快捷键终止程序),会报“possibly lost”。


    从上面分析可知,“still reachable”类型内存泄露,对内存并不影响。程序结束后,会自己主动回收它们。但也能够显示的回收该类静态成员指针内存,直接在main中delete [] Test::m_pSZ就可以。

    2)在类的静态成员函数中给静态成员变量动态分配了内存,应该在哪些地方显示的回收这些内存呢?在静态成员函数中吗?还是不论什么地方?在一篇博文中博主说:“在类的生命周期中,类的静态成员不能被delete”.假设在类的生命周期中,delete类的静态成员。会core,以下用例如以下代码測试:

    test_3.cpp

    #include <iostream>
    
    class B
    {
    private:
        static char* m_pSZ;
    public:
        inline B()
        {
            if(NULL == m_pSZ)
            {
                m_pSZ = new char[8];
            }
        }
        inline ~B()
        {
            if(m_pSZ != NULL)
            {
                delete []m_pSZ;
            }
        }
    };
    char* B::m_pSZ = NULL;
    int main()
    {
        B b;
        std::cout << "正处于类的生命周期中!" << std::endl;
        return 0;
    }
    上面代码中,m_pSZ肯定和类的生命周期一样,而对象b的生命周期肯定比m_pSZ短,但并最好还是碍,在m_pSZ生命周期之前释放内存。m_pSZ指针是静态变量,在内存的全局区域。而该指针指向的内存是堆内存,在能够获得指向堆中某段内存的指针情况下。为啥不能释放,不合规矩。

    且在实践中,经过简单的编译,执行,并没有出现dump core现象。

    使用valgrind工具检測结果例如以下:

    valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./test_3
    ==15418== Memcheck, a memory error detector
    ==15418== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
    ==15418== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
    ==15418== Command: ./test_3
    ==15418== 
    正处于类的生命周期中!


    ==15418== 
    ==15418== HEAP SUMMARY:
    ==15418==     in use at exit: 0 bytes in 0 blocks
    ==15418==   total heap usage: 1 allocs, 1 frees, 8 bytes allocated
    ==15418== 
    ==15418== All heap blocks were freed -- no leaks are possible
    ==15418== 
    ==15418== For counts of detected and suppressed errors, rerun with: -v
    ==15418== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

    所以,对于类的静态成员变量指针动态分配内存,能够在程序结束前的不论什么能够訪问静态成员变量指针的地方,对动态分配内存进行释放。也能够不显示释放,由于程序结束后,系统会自己主动回收。

    最后。对于test_3.cpp代码。在类的构造函数中动态分配内存。等于多个对象共享该静态变量指针,因此若某个对象析构了。释放了内存,其它对象若还使用该共享的静态变量指针。就是訪问空指针啦!。故更好的设计是。使用静态变量维护一个引用计数。每创建一个对象,引用计数加1。析构函数中,引用计数减一。直到为0才释放内存。代码例如以下:

    #include <iostream>
    
    class B
    {
    private:
        static char* m_pSZ;
        static unsigned int m_count;
    public:
        inline B()
        {
            if(NULL == m_pSZ)
            {
                m_pSZ = new char[8]; 
            }
            ++m_count;
            std::cout << m_count << std::endl;
        }
        inline ~B()
        {
            if(m_pSZ != NULL)
            {
                --m_count;
                if(0 == m_count)
                {
                    delete []m_pSZ;
                    m_pSZ = NULL;
                }
            }
            std::cout << m_count << std::endl;
        }
    };
    char* B::m_pSZ = NULL;
    unsigned int B::m_count = 0;
    int main()
    {
        std::cout << "正处于类的生命周期中。" << std::endl;
    
        B b;
        B b1;
        B b2;
        B b3;
        return 0;
    }




  • 相关阅读:
    5 Things Every Manager Should Know about Microsoft SharePoint 关于微软SharePoint每个经理应该知道的五件事
    Microsoft SharePoint 2010, is it a true Document Management System? 微软SharePoint 2010,它是真正的文档管理系统吗?
    You think you use SharePoint but you really don't 你认为你使用了SharePoint,但是实际上不是
    Introducing Document Management in SharePoint 2010 介绍SharePoint 2010中的文档管理
    Creating Your Own Document Management System With SharePoint 使用SharePoint创建你自己的文档管理系统
    MVP模式介绍
    权重初始化的选择
    机器学习中线性模型和非线性的区别
    神经网络激励函数的作用是什么
    深度学习中,交叉熵损失函数为什么优于均方差损失函数
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/6826320.html
Copyright © 2020-2023  润新知