代码之家  ›  专栏  ›  技术社区  ›  Elazar Leibovich

在实时环境中用C++预分配内存

  •  7
  • Elazar Leibovich  · 技术社区  · 16 年前

    我有一个函数,它的输入缓冲区为 n 字节,需要的辅助缓冲区为 n 字节以处理给定的输入缓冲区。

    (我知道vector在运行时分配内存,假设我使用的是一个使用静态预分配内存的向量。想象一下 不是 STL向量

    通常的方法是

    void processData(vector<T> &vec) {
        vector<T> &aux = new vector<T>(vec.size()); //dynamically allocate memory
        // process data
    }
    //usage:
    processData(v)
    

    因为我在一个实时的环境中工作,所以我希望预先分配我需要的所有内存。

    启动时只分配一次缓冲区。我希望每当我分配一个向量时,我会自动为我的 processData 功能。

    我可以用模板函数做类似的事情

    static void _processData(vector<T> &vec,vector<T> &aux) {
         // process data
    }
    template<size_t sz>
    void processData(vector<T> &vec) {
        static aux_buffer[sz];
        vector aux(vec.size(),aux_buffer); // use aux_buffer for the vector
        _processData(vec,aux);
    }
    // usage:
    processData<V_MAX_SIZE>(v);
    

    但是,使用模板进行大量工作并不是很有趣(现在让我们重新编译所有内容,因为我更改了注释!)当我使用这个函数时,它强制我做一些簿记。

    有没有更好的设计来解决这个问题?

    8 回复  |  直到 16 年前
        1
  •  3
  •   AProgrammer    16 年前

    我不明白你怎么能准确地得到你所描述的。像这样的事情对你来说是一个很好的妥协。

    void processData(vector<T>& vec)
    {
        static vector<T> aux(vec.size());
        if (vec.size() > aux.size()) {
           aux.resize(vec.size());
        }
        ...
    }
    
        2
  •  1
  •   peterchen    16 年前

    vector aux(vec.size(),aux_buffer); // use aux_buffer for the vector

    这是STL的新版本吗?还是自定义扩展?

    典型的解决方案是使用自定义分配器。然而,在代码中这并不一定“更漂亮”。

    Some intro slides (警告:PowerPoint!)
    Wikipedia
    Google

        3
  •  1
  •   Paul R    16 年前

    即使你成功地做到了这一点,它也可能达不到你想要的。根据您使用的操作系统以及它如何实现虚拟内存,您可能会发现 lazy allocation ,其中只实际分配和映射了内存分配的一部分,随后由于页面错误而映射了更多的页面。如果你的操作系统 mlock 或者等效的,那么你就可以解决这个问题了。

        4
  •  1
  •   Cubbi    16 年前

    我认为您可以在启动时预先分配和mlock()足够大的内存池,然后使用带有内存池分配器的常规stl容器。( Boost 属于 FSBA 或者你自己的。

    我在为我们的实时软件研究这个问题,但是测试表明内存分配在我们的硬件上对于我们的目的来说足够快。

        5
  •  1
  •   Alsk    16 年前

    假设我用的是向量 使用静态预分配内存

    然后,您应该能够在编译时获得预分配内存的大小(或最大大小)。 如果这样一个向量的大小作为模板参数,那么使用processdata函数将更容易。

    template<class T, size_t sz>
    class vector 
    { 
     enum { size = sz } //either max size
    ...
    }
    
    template<class Vector>
    static void _processData(Vector &vec,Vector &aux)
    {
         // process data
    }
    template<class Vector>
    void processData(Vector &vec) {
        static aux_buffer[Vector::size];
        //no need to pass size into constructor, as Vector type knows it already
        Vector aux(aux_buffer); // use aux_buffer for the vector
        _processData(vec,aux);
    }
    // usage:
    vector<int, 30> v1;
    vector<float, 40> v2;
    //no need to specify template parameter explicitly
    //every call uses its own function instance and its own buffer of different size
    processData(v1);
    processData(v2);
    
        6
  •  1
  •   Matthieu M.    16 年前

    这不是 vector 你需要担心的是,它是内存分配器。

    您可以完美地创建一个内存分配器,它预先分配内存,然后在构建向量时将其传递给向量,这就是 Alloc 模板参数用于!

    要确保内存没有“虚拟”分配,请在分配内存时触摸它。

    scoped_array<byte> buffer = new byte[SIZE];
    memset(buffer.get(), 0, SIZE);
    

    现在,您“只是”必须实现一个引用这个内存池的自定义分配器,并将其传递给向量实现:)

        7
  •  0
  •   Michael Kristofik    16 年前

    可以创建一个包含向量和大小相等的缓冲区的小型结构吗?然后你的向量会把它的处理缓冲带到任何地方。如果通过引用或指针传递,则应避免复制开销。伪代码如下:

    struct Container
    {
        vector<T> vec;
        vector<T> buf;
    
        Container(int size)
        {
            vec.reserve(size);
            buf.reserve(size);
        }
    };
    

    当前接受向量参数的任何函数都将接受 Container .

        8
  •  0
  •   Spille    16 年前

    可能您可以重写new和delete操作符,但是您将不得不管理 你自己的全部记忆。您可以在开始时分配所需的内存:

    void* operator new (std::size_t size) throw (std::bad_alloc);
    void* operator new[] (std::size_t size) throw (std::bad_alloc);
    void operator delete (void* ptr) throw ();
    void operator delete[] (void* ptr) throw ();