fix memory leak in VSliceAlloc

This commit is contained in:
nroskill
2022-11-02 18:38:16 +00:00
committed by wangzelin.wzl
parent 1432398f97
commit 73ddc419a0
4 changed files with 70 additions and 6 deletions

View File

@ -131,9 +131,11 @@ public:
} }
public: public:
uint32_t total() { return total_; } uint32_t total() { return total_; }
int32_t stock() { return stock_; }
int32_t remain() { return stock_ > K ? stock_ - K : (stock_ < 0 ? stock_ + K : stock_); }
bool acquire() { return dec_if_gt(K, K) > K; } bool acquire() { return dec_if_gt(K, K) > K; }
bool release() { return faa(-K) > 0; } bool release() { return faa(-K) > 0; }
bool recyle() { bool recycle() {
int32_t total = total_; int32_t total = total_;
return inc_if_lt(2 * K, -K + total) == -K + total; return inc_if_lt(2 * K, -K + total) == -K + total;
} }
@ -271,13 +273,37 @@ public:
LIB_LOG(INFO, "ObSliceAlloc init finished", K(bsize_), K(isize_), K(slice_limit_), KP(tmallocator_)); LIB_LOG(INFO, "ObSliceAlloc init finished", K(bsize_), K(isize_), K(slice_limit_), KP(tmallocator_));
} }
~ObSliceAlloc() { ~ObSliceAlloc() {
tmallocator_ = NULL; destroy();
} }
int init(const int size, const int block_size, BlockAlloc& block_alloc, const ObMemAttr& attr) { int init(const int size, const int block_size, BlockAlloc& block_alloc, const ObMemAttr& attr) {
int ret = common::OB_SUCCESS; int ret = common::OB_SUCCESS;
new(this)ObSliceAlloc(size, attr, block_size, block_alloc, NULL); new(this)ObSliceAlloc(size, attr, block_size, block_alloc, NULL);
return ret; return ret;
} }
void destroy() {
for(int i = MAX_ARENA_NUM - 1; i >= 0; i--) {
Arena& arena = arena_[i];
Block* old_blk = arena.clear();
if (NULL != old_blk) {
blk_ref_[ObBlockSlicer::hash((uint64_t)old_blk) % MAX_REF_NUM].sync();
if (old_blk->release()) {
blk_list_.add(&old_blk->dlink_);
if (old_blk->recycle()) {
destroy_block(old_blk);
} else {
_LIB_LOG(ERROR, "there was memory leak, stock=%d, remain=%d", old_blk->stock(), old_blk->remain());
}
}
}
}
ObDLink* dlink = nullptr;
if (OB_NOT_NULL(dlink = blk_list_.top())) {
Block* blk = CONTAINER_OF(dlink, Block, dlink_);
_LIB_LOG(ERROR, "there was memory leak, stock=%d, remain=%d", blk->stock(), blk->remain());
}
tmallocator_ = NULL;
bsize_ = 0;
}
void set_nway(int nway) { void set_nway(int nway) {
if (nway <= 0) { if (nway <= 0) {
nway = 1; nway = 1;
@ -351,6 +377,7 @@ public:
Block* blk = item->host_; Block* blk = item->host_;
#ifndef NDEBUG #ifndef NDEBUG
abort_unless(blk->get_slice_alloc() == this); abort_unless(blk->get_slice_alloc() == this);
abort_unless(bsize_ != 0);
#else #else
if (this != blk->get_slice_alloc()) { if (this != blk->get_slice_alloc()) {
LIB_LOG(ERROR, "blk is freed or alloced by different slice_alloc", K(this), K(blk->get_slice_alloc())); LIB_LOG(ERROR, "blk is freed or alloced by different slice_alloc", K(this), K(blk->get_slice_alloc()));
@ -391,7 +418,7 @@ private:
} }
void add_to_blist(Block* blk) { void add_to_blist(Block* blk) {
blk_list_.add(&blk->dlink_); blk_list_.add(&blk->dlink_);
if (blk->recyle()) { if (blk->recycle()) {
destroy_block(blk); destroy_block(blk);
} }
} }

View File

@ -25,6 +25,7 @@ namespace common
extern ObBlockAllocMgr default_blk_alloc; extern ObBlockAllocMgr default_blk_alloc;
class ObBlockVSlicer class ObBlockVSlicer
{ {
friend class ObVSliceAlloc;
public: public:
static const uint32_t ITEM_MAGIC_CODE = 0XCCEEDDF1; static const uint32_t ITEM_MAGIC_CODE = 0XCCEEDDF1;
static const uint32_t ITEM_MAGIC_CODE_MASK = 0XFFFFFFF0; static const uint32_t ITEM_MAGIC_CODE_MASK = 0XFFFFFFF0;
@ -72,6 +73,7 @@ private:
class ObVSliceAlloc : public common::ObIAllocator class ObVSliceAlloc : public common::ObIAllocator
{ {
friend class ObBlockVSlicer;
public: public:
enum { MAX_ARENA_NUM = 32, DEFAULT_BLOCK_SIZE = OB_MALLOC_NORMAL_BLOCK_SIZE }; enum { MAX_ARENA_NUM = 32, DEFAULT_BLOCK_SIZE = OB_MALLOC_NORMAL_BLOCK_SIZE };
typedef ObBlockAllocMgr BlockAlloc; typedef ObBlockAllocMgr BlockAlloc;
@ -91,12 +93,31 @@ public:
ObVSliceAlloc(): nway_(0), bsize_(0), blk_alloc_(default_blk_alloc) {} ObVSliceAlloc(): nway_(0), bsize_(0), blk_alloc_(default_blk_alloc) {}
ObVSliceAlloc(const ObMemAttr &attr, int block_size = DEFAULT_BLOCK_SIZE, BlockAlloc &blk_alloc = default_blk_alloc) ObVSliceAlloc(const ObMemAttr &attr, int block_size = DEFAULT_BLOCK_SIZE, BlockAlloc &blk_alloc = default_blk_alloc)
: nway_(1), bsize_(block_size), mattr_(attr), blk_alloc_(blk_alloc) {} : nway_(1), bsize_(block_size), mattr_(attr), blk_alloc_(blk_alloc) {}
virtual ~ObVSliceAlloc() override {} virtual ~ObVSliceAlloc() override { destroy(); }
int init(int block_size, BlockAlloc& block_alloc, const ObMemAttr& attr) { int init(int block_size, BlockAlloc& block_alloc, const ObMemAttr& attr) {
int ret = OB_SUCCESS; int ret = OB_SUCCESS;
new(this)ObVSliceAlloc(attr, block_size, block_alloc); new(this)ObVSliceAlloc(attr, block_size, block_alloc);
return ret; return ret;
} }
void destroy() {
for(int i = MAX_ARENA_NUM - 1; i >= 0; i--) {
Arena& arena = arena_[i];
Block* old_blk = arena.clear();
if (NULL != old_blk) {
int64_t old_pos = INT64_MAX;
if (old_blk->freeze(old_pos)) {
arena.sync();
if (old_blk->retire(old_pos)) {
destroy_block(old_blk);
} else {
// can not monitor all leak !!!
LIB_LOG(ERROR, "there was memory leak", K(old_blk->ref_));
}
}
}
}
bsize_ = 0;
}
void set_nway(int nway) { void set_nway(int nway) {
if (nway <= 0) { if (nway <= 0) {
nway = 1; nway = 1;
@ -182,12 +203,13 @@ public:
#ifdef OB_USE_ASAN #ifdef OB_USE_ASAN
::free(p); ::free(p);
#else #else
if (bsize_ > 0 && NULL != p) { if (NULL != p) {
Block::Item* item = (Block::Item*)p - 1; Block::Item* item = (Block::Item*)p - 1;
abort_unless(Block::ITEM_MAGIC_CODE == item->MAGIC_CODE_); abort_unless(Block::ITEM_MAGIC_CODE == item->MAGIC_CODE_);
Block* blk = item->host_; Block* blk = item->host_;
#ifndef NDEBUG #ifndef NDEBUG
abort_unless(blk->get_vslice_alloc() == this); abort_unless(blk->get_vslice_alloc() == this);
abort_unless(bsize_ != 0);
#else #else
if (this != blk->get_vslice_alloc()) { if (this != blk->get_vslice_alloc()) {
LIB_LOG(ERROR, "blk is freed or alloced by different vslice_alloc", K(this), K(blk->get_vslice_alloc())); LIB_LOG(ERROR, "blk is freed or alloced by different vslice_alloc", K(this), K(blk->get_vslice_alloc()));

View File

@ -182,10 +182,18 @@ struct ShareMemMgrTag { };
/* Don't use this mode unless you know what it means. */ /* Don't use this mode unless you know what it means. */
struct UniqueMemMgrTag { }; struct UniqueMemMgrTag { };
// avoid allocator destructed before HashMap
template <typename Key, typename Value, typename MemMgrTag>
struct ConstructGuard
{
public:
ConstructGuard();
};
template <typename Key, typename Value, typename MemMgrTag = ShareMemMgrTag> template <typename Key, typename Value, typename MemMgrTag = ShareMemMgrTag>
class ObLinearHashMap class ObLinearHashMap : public ConstructGuard<Key, Value, MemMgrTag>
{ {
friend class ConstructGuard<Key, Value, MemMgrTag>;
private: private:
/* Entry. */ /* Entry. */
struct Node struct Node
@ -2372,6 +2380,12 @@ bool ObLinearHashMap<Key, Value, MemMgrTag>::DoRemoveIfOnBkt<Function>::operator
return true; return true;
} }
template <typename Key, typename Value, typename MemMgrTag>
ConstructGuard<Key, Value, MemMgrTag>::ConstructGuard()
{
auto& t = ObLinearHashMap<Key, Value, MemMgrTag>::HashMapMemMgrCore::get_instance();
}
} }
} }

View File

@ -283,6 +283,7 @@ TEST_F(TestIOStruct, IOAllocator)
TEST_F(TestIOStruct, IORequest) TEST_F(TestIOStruct, IORequest)
{ {
ObTenantIOManager tenant_io_mgr; ObTenantIOManager tenant_io_mgr;
tenant_io_mgr.inc_ref();
ASSERT_SUCC(tenant_io_mgr.io_allocator_.init(TEST_TENANT_ID, IO_MEMORY_LIMIT)); ASSERT_SUCC(tenant_io_mgr.io_allocator_.init(TEST_TENANT_ID, IO_MEMORY_LIMIT));
ObRefHolder<ObTenantIOManager> holder(&tenant_io_mgr); ObRefHolder<ObTenantIOManager> holder(&tenant_io_mgr);
ObIOFd fd; ObIOFd fd;