我遇到了一种奇怪的行为。在我的代码中,一个变量减少了,但没有增加,因此我的算法不起作用。变量名称为blocksAvailable
,它在Chunk
类中定义,以Chunk::init
方法启动,以Chunk::allocate
方法递减,并且必须以Chunk::deallocate
方法递增。因此,仅在两个地方提到了此变量-allocate
和deallocate
方法。在一个地方,它递减(并且有效),而在另一个地方,它递减并且不起作用。这是完全最小化和可复制的代码:
#include <cstddef>
#include <iostream>
#include <vector>
using uchar = unsigned char;
class Chunk
{
private:
friend class FixedAllocator;
void init(size_t blockSize, uchar blocks);
void release();
void* allocate(size_t blockSize);
void deallocate(void* p, size_t blockSize);
inline bool hasBlock(void* p, size_t chunkLen) const
{
uchar * pc = static_cast<uchar*>(p);
return (pData <= pc) && (pc <= (pData + chunkLen));
}
inline bool releasable(uchar numBlocks) const
{
return blocksAvailable == numBlocks;
}
uchar* pData;
uchar firstAvailableBlock, blocksAvailable;
};
void Chunk::init(size_t blockSize, uchar blocks)
{
// for n of Ts it will allocate n * sizeof(T) memory
pData = new uchar[blockSize * blocks];
firstAvailableBlock = 0;
blocksAvailable = blocks;
uchar i = 0;
uchar* p = pData;
// used by allocate method to move forward firstAvailableBlock
for (; i != blocks; p += blockSize)
{
*p = ++i;
}
}
void Chunk::release()
{
::operator delete(pData);
}
void* Chunk::allocate(size_t blockSize)
{
if (!blocksAvailable) return 0;
// move firstAvailableBlock one block ahead
uchar* pResult = pData + firstAvailableBlock * blockSize;
firstAvailableBlock = *pResult;
--blocksAvailable;
std::cout << "blocksAvailable after allocate " << blocksAvailable << std::endl;
return pResult;
}
void Chunk::deallocate(void* p, size_t blockSize)
{
uchar* toRelease = static_cast<uchar*>(p);
// find last but one available block
firstAvailableBlock = static_cast<uchar>((toRelease - pData) / blockSize);
++blocksAvailable;
std::cout << "blocksAvailable after deallocate " << blocksAvailable << std::endl;
}
class FixedAllocator
{
private:
size_t blockSize;
uchar blocks;
using Chunks = std::vector<Chunk>;
Chunks chunks;
Chunk* allocChunk;
public:
FixedAllocator();
~FixedAllocator();
void init(size_t blockSize, size_t pageSize);
const int blockOwner(void* p) const;
void * allocate();
void deallocate(void* p);
};
FixedAllocator::FixedAllocator()
:blockSize(0),
blocks(0),
chunks(0),
allocChunk(nullptr)
{
}
FixedAllocator::~FixedAllocator()
{
Chunks::iterator it;
for (it = chunks.begin(); it != chunks.end(); ++it)
{
it->release();
}
}
void FixedAllocator::init(size_t blockSize_, size_t pageSize)
{
blockSize = blockSize_;
size_t numBlocks = pageSize / blockSize;
blocks = static_cast<uchar>(numBlocks);
}
const int FixedAllocator::blockOwner(void* p) const
{
size_t chunkLen = blocks * blockSize;
std::vector<int>::size_type i = 0, sz = chunks.size();
for (; i < sz; i++)
{
if (chunks[i].hasBlock(p, chunkLen))
{
return i;
}
}
return -1;
}
void* FixedAllocator::allocate()
{
if (!allocChunk || allocChunk->blocksAvailable == 0)
{
Chunks::iterator i = chunks.begin();
for (;;++i)
{
if (i == chunks.end())
{
// allocate memory for one more chunk
chunks.reserve(chunks.size() + 1);
Chunk newChunk;
newChunk.init(blockSize, blocks);
// add new chunk to memory pool
chunks.push_back(newChunk);
// points to new just initiated chunk
allocChunk = &chunks.back();
break;
}
if (i->blocksAvailable > 0)
{
// points to chunk with available blocks
allocChunk = &*i;
break;
}
}
}
return allocChunk->allocate(blockSize);
}
void FixedAllocator::deallocate(void* p)
{
// TODO. Optimize. Now very bruteforce and non-efficient
const int chunkPos = blockOwner(p);
if (chunkPos != -1)
{
Chunk chunk = chunks[chunkPos];
chunk.deallocate(p, blockSize);
// if chunk is releasable, release memory
if (chunk.releasable(blocks))
{
chunk.release();
chunks.erase(chunks.begin() + chunkPos);
// allocChunk may point to deleted chunk
// so, reset it
allocChunk = &chunks.back();
} else {
// there are free blocks in chunk
// so, reset allocChunk for faster future allocation
allocChunk = &chunk;
}
}
}
int main() {
FixedAllocator* alloc = new FixedAllocator();
alloc->init(4, 12);
void* p = alloc->allocate();
void* q = alloc->allocate();
void* r = alloc->allocate();
alloc->deallocate(p);
alloc->deallocate(q);
alloc->deallocate(r);
return 0;
}
如您所见,我的代码中有两个调试语句。一种在递增后打印
blocksAvailable
值,另一种在递减后打印blocksAvailable
值。但这是我在编译和运行代码时在屏幕上看到的内容:
如您所见,
3
用值allocate
初始化,然后递减3次(对deallocate
方法的三个调用),但是在每次递减(对1
的调用)之后,其值保持不变-ojit_code。这确实使我发疯,并且在我的代码中看起来有些鬼。您可以轻松地复制,编译和运行它,就像:$ g++ main.cpp
$ ./a.out
我希望有人可以帮助我找到这个幽灵从何而来。
最佳答案
这是代码中唯一可调用Chunk::deallocate
的位置:
Chunk chunk = chunks[chunkPos];
chunk.deallocate(p, blockSize);
第一行复制了
Chunk
;第二行在其上调用deallocate
,这会增加chunk.blocksAvailable
。但是chunk
只是数据的副本。对其进行修改没有持久作用。特别是,
chunks[chunkPos]
不受影响,仍然包含blocksAvailable = 0
。关于c++ - 无符号char变量不增加,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48095828/