【问题标题】:Call to _freea really necessary?调用_freea 真的有必要吗?
【发布时间】:2010-10-18 14:29:23
【问题描述】:

我正在使用 DevStudio 在 Windows 上以非托管的 C/C++ 进行开发。

我想在堆栈而不是堆上分配一些内存,因为我不想手动释放该内存(我知道智能指针和所有这些事情。我有一个非常具体的内存案例我需要处理的分配),类似于使用 A2W() 和 W2A() 宏。

_alloca 会这样做,但已被弃用。建议改用 malloca。但是 _malloca 文档说每次调用 _malloca 都必须调用 ___freea。然后它破坏了我使用 _malloca 的目的,我将使用 malloc 或 new。

任何人都知道我是否可以不调用 _freea 而不泄漏以及内部影响是什么?

否则,我最终将只使用已弃用的 _alloca 函数。

【问题讨论】:

  • 请注意,_alloca 的弃用不是基于“将在未来版本的 CRT 中删除”,而是因为“存在更安全的替代品”。与旨在提供过渡期的弃用不同,此类弃用用于提高对可能问题的认识的特定目的。我会说,如果您知道大小不会很大,只需使用 _alloca。

标签: windows stack memory-management


【解决方案1】:

如果您使用_malloca(),那么您必须调用_freea() 以防止内存泄漏,因为_malloca() 可以在堆栈或堆上进行分配。如果给定大小超过_ALLOCA_S_THRESHOLD 值,它会在堆上分配。因此,调用_freea() 更安全,如果分配发生在堆栈上,它不会做任何事情。

如果您使用的是_alloca(),从今天起似乎已被弃用;由于分配发生在堆栈上,因此无需调用 _freea()

【讨论】:

    【解决方案2】:

    我之前回答过这个问题,但我错过了一些基本的东西,这意味着它只能在调试模式下工作。我将对 _malloca 的调用移到一个可以自动释放的类的构造函数中。

    在调试中这很好,因为它总是在堆上分配。但是在release的时候是在栈上分配的,从构造函数返回后,栈指针被重置,内存丢失了。

    我返回并采用了不同的方法,结果结合使用宏 (eurgh) 来分配内存并实例化一个将在该内存上自动调用 _freea 的对象。由于它是一个宏,它被分配在同一个堆栈帧中,因此实际上可以在释放模式下工作。它和我的课一样方便,但使用起来略逊一筹。

    我做了以下事情:

    class EXPORT_LIB_CLASS CAutoMallocAFree
    {
    public:
        CAutoMallocAFree( void *pMem ) : m_pMem( pMem ) {}
        ~CAutoMallocAFree() { _freea( m_pMem ); }
    
    private:
        void    *m_pMem;
    
        CAutoMallocAFree();
        CAutoMallocAFree( const CAutoMallocAFree &rhs );
        CAutoMallocAFree &operator=( const CAutoMallocAFree &rhs );
    };
    
    #define AUTO_MALLOCA( Var, Type, Length ) \
        Type* Var = (Type *)( _malloca( ( Length ) * sizeof ( Type ) ) ); \
        CAutoMallocAFree __MALLOCA_##Var( (void *) Var );
    

    这样我可以使用下面的宏调用进行分配,并且在实例化的类超出范围时释放它:

                AUTO_MALLOCA( pBuffer, BYTE, Len );
                Ar.LoadRaw( pBuffer, Len );
    

    对于发布明显错误的内容,我深表歉意!

    【讨论】:

      【解决方案3】:

      要考虑的另一件事是使用 RAII 类来管理分配 - 当然,这只有在您的宏(或其他)可以限制为 C++ 时才有用。

      如果您出于性能原因想避免撞到堆,请查看 Matthew Wilson 的 auto_buffer<> 模板类 (http://www.stlsoft.org/doc-1.9/classstlsoft_1_1auto__buffer.html) 使用的技术。这将在堆栈上分配,除非您的运行时大小请求超过编译器时指定的大小 - 因此您可以获得大多数分配的无堆分配速度(如果您正确调整模板大小),但如果超过那个尺寸。

      由于 STLsoft 在处理可移植性问题方面有很多麻烦,您可能需要查看在 Wilson 的书中描述的 auto_buffer<> 的更简单版本,"Imperfect C++".

      我发现它在嵌入式项目中非常方便。

      【讨论】:

      • 对 auto_buffer 建议+1。它基本上是在做 _malloca 所做的,而不是 Windows 上的 _alloca。有一项检查可确保您不会超出堆栈限制,并且如果需要,它将进行堆分配而不是堆栈分配。不过,这也适用于 C。
      【解决方案4】:

      在每次调用 _malloca 之后调用 _freea 总是很重要的。

      _malloca 与 _alloca 类似,但为您的保护添加了一些额外的安全检查和增强功能。因此,_malloca 可以在堆而不是堆栈上进行分配。如果发生这种情况,而您没有调用 _freea,则会发生内存泄漏。

      在调试模式下,_malloca 总是在堆上分配,所以也应该被释放。

      搜索 _ALLOCA_S_THRESHOLD 以了解有关阈值如何工作的详细信息,以及为什么存在 _malloca 而不是 _alloca,这应该是有意义的。


      编辑:

      已经有 cmets 建议这个人只是在堆上分配,并使用智能指针等。

      堆栈分配有很多优点,_malloca 将为您提供,所以有理由想要这样做。 _alloca 将以相同的方式工作,但更有可能导致堆栈溢出或其他问题,不幸的是它没有提供很好的异常,而是倾向于仅仅破坏你的进程。 _malloca 在这方面更安全,并且可以保护您,但代价是您仍然需要使用 _freea 释放内存,因为 _malloca 可能(但在释放模式下不太可能)选择在堆上而不是在堆栈上分配。

      如果您的唯一目标是避免释放内存,我建议您使用智能指针,以便在成员超出范围时为您处理内存释放。这将在堆上分配内存,但要安全,并防止您不得不释放内存。不过,这只适用于 C++ - 如果您使用的是普通的 C,这种方法将不起作用。

      如果您出于其他原因尝试在堆栈上分配(通常是性能,因为堆栈分配非常非常快),我建议您使用 _malloca 并接受这样一个事实,即您需要在您的值上调用 _freea .

      【讨论】:

      • 只是好奇,但为什么对 Mitch 和我的帖子投反对票?我想知道为什么有人不同意这个评论......尤其是如果我遗漏了什么。
      【解决方案5】:

      如果您担心必须释放临时内存,并且您对智能指针之类的事情了如指掌,那么为什么不使用类似的模式来释放超出范围的内存呢?

      template <class T>
      class TempMem
      {
        TempMem(size_t size)
        {
          mAddress = new T[size];
        }
      
        ~TempMem
        {
          delete [] mAddress;
        }
      
        T* mAddress;
      }
      
      void foo( void )
      {
        TempMem<int> buffer(1024);
      
        // alternatively you could override the T* operator..
        some_memory_stuff(buffer.mAddress);
      
        // temp-mem auto-freed
      }
      

      【讨论】:

        【解决方案6】:

        要在堆栈上分配内存,只需声明一个适当类型和大小的变量。

        【讨论】:

        • 这不是我的反对意见,但我猜只是因为他专门询问 _alloca/_malloca,它们的堆栈使用模式与标准变量声明非常不同。不过,就我个人而言,我也会投票给你,因为在大多数情况下,如果可能的话,我会这样做。
        • 您不能使用简单的变量在堆栈上动态分配内存块。例如, unsigned char dataBlock[tempStorageSize] 不会编译。它需要在编译时知道分配块的大小。
        • @philibertperusse :我知道这一点。发帖者最初询问如何在堆栈上分配。
        猜你喜欢
        • 2018-04-05
        • 2021-01-25
        • 1970-01-01
        • 2017-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-11
        相关资源
        最近更新 更多