📄 pool.h
字号:
// pre: 'chunk' must have been previously
// returned by *this.malloc().
void free(void * const chunk)
{ store().free(chunk); }
// pre: 'chunk' must have been previously
// returned by *this.malloc().
void ordered_free(void * const chunk)
{ store().ordered_free(chunk); }
// pre: 'chunk' must have been previously
// returned by *this.malloc(n).
void ordered_free(void * const chunks, const size_type n)
{
const size_type partition_size = alloc_size();
const size_type total_req_size = n * requested_size;
const size_type num_chunks = total_req_size / partition_size +
((total_req_size % partition_size)!=0);
store().ordered_free_n(chunks, num_chunks, partition_size);
}
// pre: 'chunk' must have been previously
// returned by *this.malloc(n).
void free(void * const chunks, const size_type n)
{
const size_type partition_size = alloc_size();
const size_type total_req_size = n * requested_size;
const size_type num_chunks = total_req_size / partition_size +
static_cast<bool>( (total_req_size % partition_size) != 0 );
store().free_n(chunks, num_chunks, partition_size);
}
};
template <typename UserAllocator>
bool pool<UserAllocator>::purge_memory()
{
PODptr<size_type> iter = list;
if (!iter.valid())
return false;
do
{
// hold "next" pointer
const PODptr<size_type> next = iter.next();
// delete the storage
UserAllocator::free(iter.begin());
// increment iter
iter = next;
} while (iter.valid());
list.invalidate();
this->first = 0;
return true;
}
template <typename UserAllocator>
bool pool<UserAllocator>::release_memory()
{
// This is the return value: it will be set to true when we actually call
// UserAllocator::free(..)
bool ret = false;
// This is a current & previous iterator pair over the memory block list
PODptr<size_type> ptr = list;
PODptr<size_type> prev;
// This is a current & previous iterator pair over the free memory chunk list
// Note that "prev_free" in this case does NOT point to the previous memory
// chunk in the free list, but rather the last free memory chunk before the
// current block.
void * free = this->first;
void * prev_free = 0;
const size_type partition_size = alloc_size();
// Search through all the all the allocated memory blocks
while (ptr.valid())
{
// At this point:
// ptr points to a valid memory block
// free points to either:
// 0 if there are no more free chunks
// the first free chunk in this or some next memory block
// prev_free points to either:
// the last free chunk in some previous memory block
// 0 if there is no such free chunk
// If there are no more free memory chunks, then every remaining
// block is allocated out to its fullest capacity, and we can't
// release any more memory
if (free == 0)
return ret;
// We have to check all the chunks. If they are *all* free (i.e., present
// in the free list), then we can free the block.
bool all_chunks_free = true;
// Iterate 'i' through all chunks in the memory block
for (char * i = ptr.begin(); i != ptr.end(); i += partition_size)
{
// If this chunk is not free
if (i != free)
{
// We won't be able to free this block
all_chunks_free = false;
// Abort searching the chunks; we won't be able to free this
// block because a chunk is not free.
break;
}
// We do not increment prev_free because we are in the same block
free = nextof(free);
}
const PODptr<size_type> next = ptr.next();
if (!all_chunks_free)
{
// Rush through all free chunks from this block
std::less<void *> lt;
void * const last = ptr.end() - partition_size;
do
{
free = nextof(free);
} while (lt(free, last));
// Increment free one more time and set prev_free to maintain the
// invariants:
// free points to the first free chunk in some next memory block, or
// 0 if there is no such chunk.
// prev_free points to the last free chunk in this memory block.
prev_free = free;
free = nextof(free);
}
else
{
// All chunks from this block are free
// Remove block from list
if (prev.valid())
prev.next(next);
else
list = next;
// Remove all entries in the free list from this block
if (prev_free != 0)
nextof(prev_free) = free;
else
this->first = free;
// And release memory
UserAllocator::free(ptr.begin());
ret = true;
}
// Increment ptr
ptr = next;
}
return ret;
}
template <typename UserAllocator>
void * pool<UserAllocator>::ordered_malloc(const size_type n)
{
const size_type partition_size = alloc_size();
const size_type total_req_size = n * requested_size;
const size_type num_chunks = total_req_size / partition_size +
((total_req_size % partition_size)!=0 );
void * ret = store().malloc_n(num_chunks, partition_size);
if (ret != 0)
return ret;
// Not enougn memory in our storages; make a new storage,
next_size = max(next_size, num_chunks);
const size_type POD_size = next_size * partition_size +
min_alloc_size2 + sizeof(size_type);
char* const ptr = UserAllocator::malloc(POD_size);
if (ptr == 0)
return 0;
const PODptr<size_type> node(ptr, POD_size);
// Split up block so we can use what wasn't requested
// (we can use "add_block" here because we know that
// the free list is empty, so we don't have to use
// the slower ordered version)
if (next_size > num_chunks)
store().add_block(node.begin() + num_chunks * partition_size,
node.element_size() - num_chunks * partition_size, partition_size);
next_size <<= 1;
// insert it into the list,
// handle border case
if (!list.valid() || std::greater<void *>()(list.begin(), node.begin()))
{
node.next(list);
list = node;
}
else
{
PODptr<size_type> prev = list;
while (true)
{
// if we're about to hit the end or
// if we've found where "node" goes
if (prev.next_ptr() == 0
|| std::greater<void *>()(prev.next_ptr(), node.begin()))
break;
prev = prev.next();
}
node.next(prev.next());
prev.next(node);
}
// and return it.
return node.begin();
}
template <typename SizeType>
void * simple_segregated_storage<SizeType>::malloc_n(const size_type n,
const size_type partition_size)
{
void * start = &first;
void * iter;
do
{
if (nextof(start) == 0)
return 0;
iter = try_malloc_n(start, n, partition_size);
} while (iter == 0);
void * const ret = nextof(start);
nextof(start) = nextof(iter);
return ret;
}
template <typename SizeType>
void * simple_segregated_storage<SizeType>::find_prev(void * const ptr)
{
// Handle border case
if (first == 0 || std::greater<void *>()(first, ptr))
return 0;
void * iter = first;
while (true)
{
// if we're about to hit the end or
// if we've found where "ptr" goes
if (nextof(iter) == 0 || std::greater<void *>()(nextof(iter), ptr))
return iter;
iter = nextof(iter);
}
}
template <typename SizeType>
void * simple_segregated_storage<SizeType>::segregate(
void * const block,
const size_type sz,
const size_type partition_sz,
void * const end)
{
// Get pointer to last valid chunk, preventing overflow on size calculations
// The division followed by the multiplication just makes sure that
// old == block + partition_sz * i, for some integer i, even if the
// block size (sz) is not a multiple of the partition size.
char * old = static_cast<char *>(block)
+ ((sz - partition_sz) / partition_sz) * partition_sz;
// Set it to point to the end
nextof(old) = end;
// Handle border case where sz == partition_sz (i.e., we're handling an array
// of 1 element)
if (old == block)
return block;
// Iterate backwards, building a singly-linked list of pointers
for (char * iter = old - partition_sz; iter != block;
old = iter, iter -= partition_sz)
nextof(iter) = old;
// Point the first pointer, too
nextof(block) = old;
return block;
}
// The following function attempts to find n contiguous chunks
// of size partition_size in the free list, starting at start.
// If it succeds, it returns the last chunk in that contiguous
// sequence, so that the sequence is known by [start, {retval}]
// If it fails, it does do either because it's at the end of the
// free list or hits a non-contiguous chunk. In either case,
// it will return 0, and set start to the last considered
// chunk. You are at the end of the free list if
// nextof(start) == 0. Otherwise, start points to the last
// chunk in the contiguous sequence, and nextof(start) points
// to the first chunk in the next contiguous sequence (assuming
// an ordered free list)
template <typename SizeType>
void * simple_segregated_storage<SizeType>::try_malloc_n(
void * & start, size_type n, const size_type partition_size)
{
void * iter = nextof(start);
while (--n != 0)
{
void * next = nextof(iter);
if (next != static_cast<char *>(iter) + partition_size)
{
// next == 0 (end-of-list) or non-contiguous chunk found
start = iter;
return 0;
}
iter = next;
}
return iter;
}
template <typename UserAllocator>
void * pool<UserAllocator>::ordered_malloc_need_resize()
{
// No memory in any of our storages; make a new storage,
const size_type partition_size = alloc_size();
const size_type POD_size = next_size * partition_size +
min_alloc_size2 + sizeof(size_type);
char * const ptr = UserAllocator::malloc(POD_size);
if (ptr == 0)
return 0;
const PODptr<size_type> node(ptr, POD_size);
next_size <<= 1;
// initialize it,
// (we can use "add_block" here because we know that
// the free list is empty, so we don't have to use
// the slower ordered version)
store().add_block(node.begin(), node.element_size(), partition_size);
// insert it into the list,
// handle border case
if (!list.valid() || std::greater<void *>()(list.begin(), node.begin()))
{
node.next(list);
list = node;
}
else
{
PODptr<size_type> prev = list;
while (true)
{
// if we're about to hit the end or
// if we've found where "node" goes
if (prev.next_ptr() == 0
|| std::greater<void *>()(prev.next_ptr(), node.begin()))
break;
prev = prev.next();
}
node.next(prev.next());
prev.next(node);
}
// and return a chunk from it.
return store().malloc();
}
CL_NS_END
#endif //LUCENE_ENABLE_MEMORY_POOL
#endif //lucene_debug_pool
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -