diff --git a/deps/oblib/src/lib/allocator/ob_slice_alloc.h b/deps/oblib/src/lib/allocator/ob_slice_alloc.h index 2fc44d11c9..6c0ebfad8c 100644 --- a/deps/oblib/src/lib/allocator/ob_slice_alloc.h +++ b/deps/oblib/src/lib/allocator/ob_slice_alloc.h @@ -131,9 +131,11 @@ public: } public: 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 release() { return faa(-K) > 0; } - bool recyle() { + bool recycle() { int32_t total = 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_)); } ~ObSliceAlloc() { - tmallocator_ = NULL; + destroy(); } int init(const int size, const int block_size, BlockAlloc& block_alloc, const ObMemAttr& attr) { int ret = common::OB_SUCCESS; new(this)ObSliceAlloc(size, attr, block_size, block_alloc, NULL); 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) { if (nway <= 0) { nway = 1; @@ -351,6 +377,7 @@ public: Block* blk = item->host_; #ifndef NDEBUG abort_unless(blk->get_slice_alloc() == this); + abort_unless(bsize_ != 0); #else 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())); @@ -391,7 +418,7 @@ private: } void add_to_blist(Block* blk) { blk_list_.add(&blk->dlink_); - if (blk->recyle()) { + if (blk->recycle()) { destroy_block(blk); } } diff --git a/deps/oblib/src/lib/allocator/ob_vslice_alloc.h b/deps/oblib/src/lib/allocator/ob_vslice_alloc.h index 2aeb81eb3a..d3d4be95e9 100644 --- a/deps/oblib/src/lib/allocator/ob_vslice_alloc.h +++ b/deps/oblib/src/lib/allocator/ob_vslice_alloc.h @@ -25,6 +25,7 @@ namespace common extern ObBlockAllocMgr default_blk_alloc; class ObBlockVSlicer { + friend class ObVSliceAlloc; public: static const uint32_t ITEM_MAGIC_CODE = 0XCCEEDDF1; static const uint32_t ITEM_MAGIC_CODE_MASK = 0XFFFFFFF0; @@ -72,6 +73,7 @@ private: class ObVSliceAlloc : public common::ObIAllocator { + friend class ObBlockVSlicer; public: enum { MAX_ARENA_NUM = 32, DEFAULT_BLOCK_SIZE = OB_MALLOC_NORMAL_BLOCK_SIZE }; typedef ObBlockAllocMgr BlockAlloc; @@ -91,12 +93,31 @@ public: 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) : 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 ret = OB_SUCCESS; new(this)ObVSliceAlloc(attr, block_size, block_alloc); 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) { if (nway <= 0) { nway = 1; @@ -182,12 +203,13 @@ public: #ifdef OB_USE_ASAN ::free(p); #else - if (bsize_ > 0 && NULL != p) { + if (NULL != p) { Block::Item* item = (Block::Item*)p - 1; abort_unless(Block::ITEM_MAGIC_CODE == item->MAGIC_CODE_); Block* blk = item->host_; #ifndef NDEBUG abort_unless(blk->get_vslice_alloc() == this); + abort_unless(bsize_ != 0); #else 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())); diff --git a/deps/oblib/src/lib/hash/ob_linear_hash_map.h b/deps/oblib/src/lib/hash/ob_linear_hash_map.h index 18b7d9650d..34ff841603 100644 --- a/deps/oblib/src/lib/hash/ob_linear_hash_map.h +++ b/deps/oblib/src/lib/hash/ob_linear_hash_map.h @@ -182,10 +182,18 @@ struct ShareMemMgrTag { }; /* Don't use this mode unless you know what it means. */ struct UniqueMemMgrTag { }; +// avoid allocator destructed before HashMap +template +struct ConstructGuard +{ +public: + ConstructGuard(); +}; template -class ObLinearHashMap +class ObLinearHashMap : public ConstructGuard { + friend class ConstructGuard; private: /* Entry. */ struct Node @@ -2372,6 +2380,12 @@ bool ObLinearHashMap::DoRemoveIfOnBkt::operator return true; } +template +ConstructGuard::ConstructGuard() +{ + auto& t = ObLinearHashMap::HashMapMemMgrCore::get_instance(); +} + } } diff --git a/unittest/storage/test_io_manager.cpp b/unittest/storage/test_io_manager.cpp index 0fc4bb7a3c..48883882b6 100644 --- a/unittest/storage/test_io_manager.cpp +++ b/unittest/storage/test_io_manager.cpp @@ -283,6 +283,7 @@ TEST_F(TestIOStruct, IOAllocator) TEST_F(TestIOStruct, IORequest) { ObTenantIOManager tenant_io_mgr; + tenant_io_mgr.inc_ref(); ASSERT_SUCC(tenant_io_mgr.io_allocator_.init(TEST_TENANT_ID, IO_MEMORY_LIMIT)); ObRefHolder holder(&tenant_io_mgr); ObIOFd fd;