我有一个强大的用例,可以预先分配我需要的所有内存,并在完成后释放它。
我已经提出了这个真正简单的缓冲池C++实现,我必须对其进行测试,但我不确定我尝试使用的指针算法是否允许我这样做。基本上就是我下一步做并发布的部分。我更喜欢围绕这个想法的一些技巧,而不是依赖于任何类型的内存处理程序,这只会使客户端代码更加复杂。
#include <stdio.h>
#include <queue>
#include "utils_mem.h"
using namespace std;
template <class T>
class tbufferpool {
private:
const int m_initial;
const int m_size;
const int m_total;
T* m_buffer;
vector<T*> m_queue;
public:
// constructor
tbufferpool(int initial, int size) : m_initial(initial), m_size(size), m_total(initial*size*sizeof(T)) {
m_buffer = (T*) malloc(m_total);
T* next_buffer = m_buffer;
for (int i=0; i < initial; ++i, next_buffer += i*size) {
m_queue.push_back(next_buffer);
}
}
// get next buffer element from the pool
T* next() {
// check for pool overflow
if (m_queue.empty()) {
printf("Illegal bufferpool state, our bufferpool has %d buffers only.", m_initial);
exit(EXIT_FAILURE);
}
T* next_buffer = m_queue.back();
m_queue.pop_back();
return next_buffer;
}
// release element, make it available back in the pool
void release(T* buffer) {
assert(m_buffer <= buffer && buffer < (buffer + m_total/sizeof(T)));
m_queue.push_back(buffer);
}
void ensure_size(int size) {
if (size >= m_size) {
printf("Illegal bufferpool state, maximum buffer size is %d.", m_size);
exit(EXIT_FAILURE);
}
}
// destructor
virtual ~tbufferpool() {
free(m_buffer);
}
};发布于 2012-04-06 03:55:17
首先,当您增加指向T的指针时,它将指向内存中T的下一个元素。
m_queue.push(m_buffer + (i*size*sizeof(T)));这应该是这样的
m_buffer = (T*) malloc(m_total);
T* next = m_buffer;
for (int i=0; i < initial; ++i) {
m_queue.push(next++);
}第二,
assert(m_buffer <= buffer && buffer < m_total);它应该是这样的
assert(m_buffer <= buffer && buffer <= m_buffer + m_total/sizeof(T));希望它能帮上忙!
发布于 2012-04-06 03:59:40
我不明白为什么要“包装”STL queue<>容器。只需将您的“缓冲区”放入队列中,并在需要时提取地址即可。当你处理完缓冲区中的“段”时,只需将它从队列中弹出,它就会自动释放。因此,不是指向缓冲区的指针,而是实际的buffer类。
这让我觉得这是在重新发明轮子。现在,由于您需要一次分配所有内容,我将使用vector而不是queue,因为vector<>类型可以在构造时一次性分配,并且push_back()方法不会重新分配,除非需要,pop_back()也是如此。有关使用的方法,请参阅here。
不过,基本上,这是我的粗略想法:
#include <myType.h> // Defines BufferType
const int NUMBUFFERS = 30;
int main()
{
vector<BufferType> myBuffers(NUMBUFFERS);
BufferType* segment = &(myBuffers[0]); // Gets first segment
myBuffers.pop_back(); // Reduces size by one
return 0;
}我希望这能给你一个大概的概念。你可以这样使用向量中的缓冲区,并且只有一个分配或释放,如果你愿意,你可以使用类似堆栈的逻辑。dequeue类型或其他标准容器可能也值得一看,但如果只是“我只想要一个分配或释放”,我会使用向量,甚至可能使用指向数组的智能指针。
发布于 2012-04-06 07:37:02
我在使用对象池时发现了一些东西:
我不确定是否可以一次分配所有对象。我喜欢从一个'pooledObject‘类中继承我所有的池化对象,这个类包含一个对它自己的池的私有引用,所以允许一个简单的,无参数的'release’方法,并且我总是绝对确定一个对象总是被释放回它自己的池。我不确定如何使用静态数组ctor加载具有池引用的每个实例-我总是在循环中一个接一个地构造对象。
另一个有用的私有成员是一个“已分配的”布尔值,当一个对象被放入池中并在释放时被清除时,它就会被设置。这允许pool类检测,除非一个对象被释放两次。“发布两次”错误如果不能立即被检测到,可能会非常糟糕--奇怪的行为或崩溃会在几分钟后发生,而且通常发生在另一个模块的另一个线程中。最好尽快检测到双倍释放!
我发现在1秒计时器上将我的池的级别转储到状态栏中是有用的,也是令人放心的。如果发生泄漏,我可以看到它的发生,并且,通常,当一个数字惊人地下降时,通过我所在的活动来了解泄漏在哪里。谁需要Valgrind:)
在线程方面,如果您必须使您的池是线程安全的,那么使用阻塞队列会很有帮助。如果池耗尽,尝试获取对象的线程可以等待,直到它们被释放,应用程序只会减慢速度,而不是崩溃/死锁。另外,要小心re。虚假分享。您可能必须使用“填充”数组数据成员来确保没有两个对象共享一个缓存线。
https://stackoverflow.com/questions/10034839
复制相似问题