#include "UtilityCommon.h" #include "SharedMemoryPool.h" #include "LinkedListCS.h" #include "../ProgramCommon/Version.h" //================================================================================================== // Name: SharedMemoryPool // @history // 07/09/07 - CheckIn (Waverix) // 10/02/25 - remove macros '__NA000000_080816_EXSIZE_AND_MEMORY_OVERRUN_DETECT__' // 10/02/25 - changes pool leak dectector to support common utility // 10/05/10 - changes a coding style and // adds a huge size memory tokenizing header which support a memory counter // 10/05/19 - changed to first instancing approach based on singleton // 10/05/26 - detached shared code block from template implements // 11/07/05 - heap control extention and // full streaming index calculation without the bytes alignment modification // - upgrade to v0250, see the reference f110706.3L. //================================================================================================== #if USING_SUN_SHARED_POOL_REPORT // 内存泄露检测工具/Release模式也可以检测 #define USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR (1) #else // 内存泄露检测工具/Release模式也可以检测 #define USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR (0) #endif BOOST_STATIC_ASSERT(SharedMemoryPool::kVersion == 0x0250); //================================================================================================== // #define BUF_ALIGN_008(__size) (((__size)+((8)-1))&(~((8)-1))) #define BUF_ALIGN_008_BY_IDX(__idx) ((__idx)<<3) #define BUF_008_IDX_BY_SIZE(__size) ((__size)>>3) #define BUF_ALIGN_016(__size) (((__size)+((16)-1))&(~((16)-1))) #define BUF_ALIGN_016_BY_IDX(__idx) ((__idx)<<4) // 因为要计算8x,所以不能只使用这个。参考使用案例 #define BUF_016_IDX_BY_SIZE(__size) ((__size)>>4) // 上洞 #define BUF_ALIGN_032(__size) (((__size)+((32)-1))&(~((32)-1))) #define BUF_ALIGN_032_BY_IDX(__idx) ((__idx)<<5) // 因为要计算16x,所以不能只使用这个。参考使用案例 #define BUF_032_IDX_BY_SIZE(__size) ((__size)>>5) // #define BUF_ALIGN_064(__size) (((__size)+((64)-1))&(~((64)-1))) #define BUF_ALIGN_064_BY_IDX(__idx) ((__idx)<<6) // 因为要进行64x的连续计算,所以不能只使用这个。参考使用案例 #define BUF_064_IDX_BY_SIZE(__size) ((__size)>>6) // // reference pool #define BUF_ALIGN_4096(__size) (((__size)+((4096)-1))&(~((4096)-1))) #define BUF_4096_IDX_BY_SIZE(__size) ((__size)>>12) #define BUF_ALIGN_1024x1024(__size) (((__size)+((1048576)-1))&(~((1048576)-1))) #define BUF_1024x1024_IDX_BY_SIZE(__size) ((__size)>>20) namespace util { namespace memory { ; //================================================================================================== struct SharedMemoryTable; enum eCheckMemoryNodeResult { eError_NotDefined, eError_Success_PoolManagedToken, eError_Success_PoolUnmanagedToken, eError_Fail_Null_Pointer, eError_Unknown_HeapToken, eError_Fail_BufferOverrunedToken, // not control eError_Fail_CorruptedHeaderToken, // not control }; // struct SharedPoolVerifier { ulong verifier; void* next; }; //================================================================================================== // NOTE: f110526.3L, f110513.7L, this class is used by SharedMemoryPoolNode<_size> class SharedMemoryPoolSizeBased { public: struct Token; // allocated/deallocated management struct TokenBlock;// Token chunking struct MemoryForUse; // support memory struct MemoryBlockForUse; // memory chunking //---------------------------------------------------------------------------------------------- static const uint16_t kMagicCodeAlloc = ('S') | ('A'<<8); static const uint16_t kMagicCodeFree = ('s') | ('F'<<8); static const uint16_t kMagicCodeTailConv = 0x0101; // kMagicCode(Alloc/Free) (+/-) this // union UsingTag { ulong composed; struct { uint16_t size; // requested size uint16_t tag; // allocated or deallocated tag (magic key) }; }; struct TokenVerifier { UsingTag using_tag; Token* parent; }; // allocated/deallocated management struct Token : public util::__LList { UsingTag using_tag; MemoryForUse* link; const char* function; int line_no; int issued_number; }; // Token chunking struct TokenBlock : public util::__LList { #pragma warning(push) #pragma warning(disable:4200) Token stream[0]; #pragma warning(pop) }; // support memory struct MemoryForUse { TokenVerifier header[1]; // next specification //uint8_t type_stream[type_size]; // ... // TokenVerifier tail; // overrun check & comparison }; struct MemoryBlockForUse : public util::__LList { #pragma warning(push) #pragma warning(disable:4200) MemoryForUse stream[0]; // (MemoryForUse + tail + alignment) * n #pragma warning(pop) }; // struct Statistics { size_t number_of_free_nodes; size_t number_of_alloc_nodes; size_t number_of_total_blocks; size_t number_of_free_requested; size_t number_of_alloc_requested; }; //---------------------------------------------------------------------------------------------- SharedMemoryPoolSizeBased(); // not unused, brutely clread SharedMemoryPoolSizeBased(size_t type_size, size_t chunk_size); //~SharedMemoryPoolSizeBased(); <- not use destructor void* Allocate(SharedMemoryTable* const table, size_t requested_size, const char* name, const int line_no); void Deallocate(SharedMemoryTable* const table, MemoryForUse* memory_for_use); void FreeAllElements(SharedMemoryTable* const table); // const Statistics& GetStatistics() const; static MemoryForUse* CheckNodeHeader(void* element, eCheckMemoryNodeResult* const result); static size_t GetMaxMemoryForUseSize(size_t request_size); private: void AddBlock(SharedMemoryTable* const table); //---------------------------------------------------------------------------------------------- // fields... const size_t type_size_; const size_t growth_count_; // page-fit util::__LList free_list_; util::__LList alloc_list_; util::__LList total_list_; util::__LList memory_list_; Statistics statistics_; // friend struct SharedMemoryTable; __DISABLE_COPY(SharedMemoryPoolSizeBased); }; //================================================================================================== struct SharedMemoryTable { enum ePoolIndex { kSizeIndex_None = 0, // 8x based kSizeIndex_0008, // very busible access, level 5 kSizeIndex_0016, // level 4 kSizeIndex_0024, // level 4 kSizeIndex_0032, // level 4 kSizeIndex_0040, // level 4 kSizeIndex_0048, // STLX_MAP, node size, level 2 kSizeIndex_0056, kSizeIndex_0064, kSizeIndex_0072, kSizeIndex_0080, kSizeIndex_0088, kSizeIndex_0096, kSizeIndex_0104, kSizeIndex_0112, kSizeIndex_0120, kSizeIndex_0128, // 32x based kSizeIndex_0160, kSizeIndex_0192, // level 3 kSizeIndex_0224, kSizeIndex_0256, // 64x based kSizeIndex_0320, kSizeIndex_0384, kSizeIndex_0448, kSizeIndex_0512, // 128x based kSizeIndex_0640, // SCItemSlot, level 4 kSizeIndex_0768, kSizeIndex_0896, kSizeIndex_1024, kSizeIndex_1152, kSizeIndex_1280, // STLX_HASH_MAP, bucket secondary extention, level 2 kSizeIndex_1408, // kSizeIndex_Counts, }; enum ePoolInfo { //------------------------------ kSize008xUpperbound = 128, kSize032xUpperbound = 256, kSize064xUpperbound = 512, kSize128xUpperbound = 1408, kSizeOverUpperbound = kSize128xUpperbound, kStreamingSizeCounts = int(kSizeOverUpperbound / 8) + 1, // 176 + 1 }; struct TokenSizeNode { uint16_t pool_index; uint16_t token_size; }; //---------------------------------------------------------------------------------------------- SharedMemoryTable(); ~SharedMemoryTable(); // void* Allocate(size_t size, const char* name, const int line_no); void Deallocate(void* ptr); // bool ReportMemoryLeaks(const char* path_file_name); bool ReportCurrentMemoryUsages(); static void TouchMemoryLeakReportFile(const char* path_file_name); static void ReportRuntimeFailedObject(eCheckMemoryNodeResult error, void* ptr, SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use); //---------------------------------------------------------------------------------------------- uint8_t padding0_[236]; int initialized_; //HANDLE handle_token_block_; //HANDLE handle_using_block_; int issued_ordered_number_; int reference_counter_; TokenSizeNode index_by_size8x_[kStreamingSizeCounts]; uint8_t padding1_[60]; SharedMemoryPoolSizeBased size_pool_instance_[kSizeIndex_Counts]; uint8_t padding2_[256]; SharedMemoryPoolSizeBased::Statistics chunk_statistics_4096[256]; SharedMemoryPoolSizeBased::Statistics chunk_statistics_1024x1024[256]; // }; //-------------------------------------------------------------------------------------------------- SharedMemoryPoolSizeBased::MemoryForUse* _CheckPoolUnmanagedHeap( eCheckMemoryNodeResult* const result, void* element, SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use); SharedMemoryPoolSizeBased::MemoryForUse* _CheckPoolManagedHeap( eCheckMemoryNodeResult* const result, void* element, SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use); }}; //end of namespace //================================================================================================== // static heap data static void (*__fnSharedMemoryLeakDetect)(DWORD alloc_counter); static void (*__fnSharedMemoryLeakCheck)(); static uint8_t shared_memory_pool_block[sizeof(SharedMemoryPool)]; static uint8_t shared_memory_table_block[sizeof(util::memory::SharedMemoryTable)]; //================================================================================================== // implements __forceinline util::memory::SharedMemoryPoolSizeBased::MemoryForUse* util::memory::_CheckPoolUnmanagedHeap(util::memory::eCheckMemoryNodeResult* const result, void* element, util::memory::SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use) { using namespace util::memory; assert(memory_for_use->header->parent == element); SharedMemoryPoolSizeBased::TokenVerifier tail_check = *reinterpret_cast(\ reinterpret_cast(element) + memory_for_use->header->using_tag.composed); //tail_check.using_tag.tag -= SharedMemoryPoolSizeBased::kMagicCodeTailConv; if (memory_for_use->header->using_tag.composed == tail_check.using_tag.composed && memory_for_use->header->parent == tail_check.parent) { *result = eError_Success_PoolUnmanagedToken; return memory_for_use; } else if (memory_for_use->header->parent != tail_check.parent) { *result = eError_Fail_BufferOverrunedToken; return memory_for_use; } else //memory_for_use->header->using_tag.composed != tail_check->using_tag.composed { // ... *result = eError_Fail_BufferOverrunedToken; return memory_for_use; } } __forceinline util::memory::SharedMemoryPoolSizeBased::MemoryForUse* util::memory::_CheckPoolManagedHeap(util::memory::eCheckMemoryNodeResult* const result, void* element, util::memory::SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use) { using namespace util::memory; const SharedMemoryPoolSizeBased::UsingTag using_tag = memory_for_use->header->using_tag; if (using_tag.tag == util::memory::SharedMemoryPoolSizeBased::kMagicCodeAlloc || using_tag.tag == util::memory::SharedMemoryPoolSizeBased::kMagicCodeFree) { SharedMemoryPoolSizeBased::TokenVerifier tail_check = *reinterpret_cast(\ reinterpret_cast(element) + using_tag.size); tail_check.using_tag.tag -= SharedMemoryPoolSizeBased::kMagicCodeTailConv; if (using_tag.composed == tail_check.using_tag.composed) { *result = eError_Success_PoolManagedToken; return memory_for_use; } else { *result = eError_Fail_BufferOverrunedToken; return memory_for_use; }; } else { *result = eError_Fail_CorruptedHeaderToken; return memory_for_use; }; } util::memory::SharedMemoryPoolSizeBased::MemoryForUse* util::memory::SharedMemoryPoolSizeBased::CheckNodeHeader( void* element, eCheckMemoryNodeResult* const result) { MemoryForUse* memory_for_use = reinterpret_cast(element); if (memory_for_use == NULL) { *result = eError_Fail_Null_Pointer; // error: null pointer return NULL; }; --memory_for_use; if (Token* parent = memory_for_use->header->parent) { if (parent == element) { // large size token, not managed in pool return _CheckPoolUnmanagedHeap(result, element, memory_for_use); } else { // managed node in the size-based pool or normal heap containing corrupted header return _CheckPoolManagedHeap(result, element, memory_for_use); }; }; // error handling *result = eError_Unknown_HeapToken; // error: unexpected pointer, can't control return memory_for_use; }; //================================================================================================== // SharedMemoryPool implementations // #define SMPOOL_PTR() reinterpret_cast(shared_memory_pool_block) #define CHECK_SMPOOL_INSTANCED() (SMPOOL_PTR()->instanced_tag_ == kInstancedTag) #define SMROUTER_PTR(_pool_instance_) \ reinterpret_cast((_pool_instance_)->inter_block_) __forceinline SharedMemoryPool* SharedMemoryPool::Instance() { if (CHECK_SMPOOL_INSTANCED()) { return SMPOOL_PTR(); }; SharedMemoryPool::CreateInstance(); return SMPOOL_PTR(); }; bool SharedMemoryPool::CreateInstance() { if (CHECK_SMPOOL_INSTANCED()) { return true; } // initialize buffer block new (shared_memory_pool_block) SharedMemoryPool; return true; } bool SharedMemoryPool::CheckInstanced() { return CHECK_SMPOOL_INSTANCED(); } void SharedMemoryPool::DestroyInstance() { SMPOOL_PTR()->~SharedMemoryPool(); *(ulong*)shared_memory_pool_block = 0x00011000; // released dummy value } SharedMemoryPool::SharedMemoryPool() : instanced_tag_(kInstancedTag) { static bool initialized_static = false; if (initialized_static == false) { ZeroMemory(shared_memory_table_block, sizeof(shared_memory_table_block)); inter_block_ = new (shared_memory_table_block) util::memory::SharedMemoryTable; initialized_static = true; }; } SharedMemoryPool::~SharedMemoryPool() { static bool released_static = false; if (released_static == false) { if (inter_block_) { SMROUTER_PTR(this)->~SharedMemoryTable(); inter_block_ = NULL; } released_static = true; } } void* SharedMemoryPool::MemoryAllocate(size_t size, const char* name, const int line_no) { SharedMemoryPool* shared_memory_pool = SharedMemoryPool::Instance(); void* ptr = SMROUTER_PTR(shared_memory_pool)->Allocate(size, name, line_no); return ptr; } void SharedMemoryPool::MemoryDeAllocate(void* ptr) { SharedMemoryPool* shared_memory_pool = SharedMemoryPool::Instance(); if ((ptr && shared_memory_pool) == false) { return; } SMROUTER_PTR(shared_memory_pool)->Deallocate(ptr); int reference_counter = SMROUTER_PTR(shared_memory_pool)->reference_counter_; if (reference_counter < 2) { SharedMemoryPool::DestroyInstance(); } } void* SharedMemoryPool::RedirectNew_MemoryAllocate(size_t size, const char* name, const int line_no, SharedMemoryPool*) { static void* (*redirect_new_static)(size_t, const char*, const int) = \ &SharedMemoryPool::MemoryAllocate; // same as MemoryAllocate return (*redirect_new_static)(size, name, line_no); } void SharedMemoryPool::RedirectNew_MemoryDeallocate(void* ptr) { static void (*redirect_new_static)(void*) = &SharedMemoryPool::MemoryDeAllocate; return (*redirect_new_static)(ptr); } // NOTE: f110708.5L, added the token validation routine bool SharedMemoryPool::CheckValidAllocatedMemory(void* ptr) { SharedMemoryPool* shared_memory_pool = SharedMemoryPool::Instance(); if ((ptr && shared_memory_pool) == false) { return false; }; util::memory::eCheckMemoryNodeResult result = util::memory::eError_NotDefined; util::memory::SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use = \ util::memory::SharedMemoryPoolSizeBased::CheckNodeHeader(ptr, &result); __UNUSED(memory_for_use); if (result == util::memory::eError_Success_PoolManagedToken || result == util::memory::eError_Success_PoolUnmanagedToken) { return true; }; return false; }; //================================================================================================== //================================================================================================== //================================================================================================== util::memory::SharedMemoryPoolSizeBased::SharedMemoryPoolSizeBased() : type_size_(0) , growth_count_(0) { } util::memory::SharedMemoryPoolSizeBased::SharedMemoryPoolSizeBased( size_t type_size, size_t chunk_size) : type_size_(type_size) , growth_count_(chunk_size) { util::LList::Init(&free_list_); util::LList::Init(&alloc_list_); util::LList::Init(&total_list_); util::LList::Init(&memory_list_); } void* util::memory::SharedMemoryPoolSizeBased::Allocate(SharedMemoryTable* const table, size_t requested_size, const char* name, const int line_no) { if (util::LList::IsEmpty(&free_list_)) { AddBlock(table); }; Token* token = free_list_.next; util::LList::Delete(token); --statistics_.number_of_free_nodes; // token->function = name; token->line_no = line_no; token->issued_number = ++table->issued_ordered_number_; if (TokenVerifier* verifier = token->link->header) { verifier->parent = token; // must be pre-checked verifier->using_tag.size = static_cast(requested_size); verifier->using_tag.tag = this->kMagicCodeAlloc; token->using_tag = verifier->using_tag; }; uint8_t* ptr = reinterpret_cast(token->link->header + 1); if (TokenVerifier* tail = reinterpret_cast(ptr + requested_size)) { tail->parent = token; tail->using_tag = token->using_tag; tail->using_tag.tag += this->kMagicCodeTailConv; }; util::LList::AddPrev(token, &alloc_list_); ++statistics_.number_of_alloc_nodes; ++statistics_.number_of_alloc_requested; // return ptr; } void util::memory::SharedMemoryPoolSizeBased::Deallocate(SharedMemoryTable* const table, MemoryForUse* memory_for_use) { __UNUSED(table); // validated memory_for_use Token* const token = memory_for_use->header->parent; if (token->link != memory_for_use || token->using_tag.composed != memory_for_use->header->using_tag.composed || token->using_tag.tag != this->kMagicCodeAlloc || util::LList::IsEmpty(&alloc_list_)) { #if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR // memory leak occurrence if (token->function != NULL && ::IsBadReadPtr(token->function, sizeof(char*))) { token->function = NULL; }; uint8_t* used_ptr = reinterpret_cast(memory_for_use->header + 1); SUNLOG(eCRITICAL_LOG, _T("|MemoryCheckReport|斤口=unexpected free operation") _T("|MemInfo=size(%d), tag([%02X:%02X])|Suspicious Location='%s', %d lines") _T("|Dump=[%02X][%02X][%02X][%02X]|"), token->function, token->line_no, token->using_tag.size, (token->using_tag.tag & 0xFF), ((token->using_tag.tag >> 8) & 0xFF), used_ptr[0], used_ptr[1], used_ptr[2], used_ptr[3]); #endif #ifdef _SERVER assert(!"corrupted!"); #else ASSERT(!"corrupted!"); #endif return; } else { // validated memory ulong* dest_it = reinterpret_cast(memory_for_use + 1); const ulong* const dest_upperbound = &dest_it[this->type_size_ >> 2]; for (; dest_it < dest_upperbound; ++dest_it) { *dest_it = 0xFEEEEEEE; }; }; //---------------------------------------------------------------------------------------------- ;{ util::LList::Delete(token); --statistics_.number_of_alloc_nodes; util::LList::AddPrev(token, &free_list_); ++statistics_.number_of_free_nodes; // ++statistics_.number_of_free_requested; }; // if (UsingTag* tag = &token->using_tag) { tag->composed = 0; tag->tag = this->kMagicCodeFree; }; } __forceinline size_t util::memory::SharedMemoryPoolSizeBased::GetMaxMemoryForUseSize(size_t request_size) { //assert(request_size != 0 && BUF_ALIGN_008(request_size) == request_size); // header body tail size_t block_size = sizeof(MemoryForUse) + BUF_ALIGN_008(request_size) + sizeof(TokenVerifier); assert(block_size == BUF_ALIGN_008(block_size)); return block_size; }; void util::memory::SharedMemoryPoolSizeBased::AddBlock(SharedMemoryTable* const table) { __UNUSED(table); const size_t token_array_size = sizeof(TokenBlock) + (sizeof(Token) * growth_count_); const size_t one_token_memory_for_use = GetMaxMemoryForUseSize(type_size_); const size_t chunked_elements_size = sizeof(MemoryBlockForUse) + (growth_count_ * one_token_memory_for_use); // TokenBlock* const block = (TokenBlock*)::HeapAlloc(\ ::GetProcessHeap(), 0, token_array_size); ;{ ZeroMemory(block, token_array_size); util::LList::Init(block); util::LList::AddPrev(block, &total_list_); ++statistics_.number_of_total_blocks; }; MemoryBlockForUse* const use_block = (MemoryBlockForUse*)::malloc(chunked_elements_size); //(MemoryBlockForUse*)::HeapAlloc(table->handle_using_block_, 0, chunked_elements_size); ;{ util::LList::Init(use_block); util::LList::AddPrev(use_block, &memory_list_); // same 'statistics_.number_of_total_blocks' }; Token* token = block->stream; MemoryForUse* memory_for_use = use_block->stream; #define NextMemoryForUse(__ptr__) \ reinterpret_cast(reinterpret_cast(__ptr__) + one_token_memory_for_use) for (size_t i = 0; i < growth_count_; ++i, ++token, (memory_for_use = NextMemoryForUse(memory_for_use))) { // init tokens util::LList::Init(token); token->link = memory_for_use; if (UsingTag* tag = &token->using_tag) { tag->composed = 0; tag->tag = this->kMagicCodeFree; memory_for_use->header->parent = token; memory_for_use->header->using_tag = token->using_tag; }; util::LList::AddPrev(token, &free_list_); ++statistics_.number_of_free_nodes; }; } #if _BUILD_FLAG_SHARED_MEMORY_NEWDEL_SYNC_CHECK_ void util::memory::SharedMemoryPoolSizeBased::DeadBeef(Element* element) { int* it = &element->deadBeef; int* itend = (int*)((byte*)element + elementSize_); while(it < itend) *it++ = 0xDEADBEEF; } #endif //------------------------------------------------------------------------------ // () // name: // usage: void util::memory::SharedMemoryPoolSizeBased::FreeAllElements(SharedMemoryTable* const table) { __UNUSED(table); ;{ size_t counter = 0; TokenBlock* root = static_cast(&total_list_); TokenBlock* token = root->next; while (token != root) { TokenBlock* next_token = util::LList::Delete(token); ::HeapFree(::GetProcessHeap(), 0, token); token = next_token; ++counter; }; ASSERT(statistics_.number_of_total_blocks == counter); }; ;{ size_t counter = 0; MemoryBlockForUse* root = static_cast(&memory_list_); MemoryBlockForUse* token = root->next; while (token != root) { MemoryBlockForUse* next_token = util::LList::Delete(token); ::free(token); //::HeapFree(table->handle_using_block_, 0, token); token = next_token; ++counter; }; ASSERT(statistics_.number_of_total_blocks == counter); }; ZeroMemory(&statistics_, sizeof(statistics_)); } //================================================================================================== //================================================================================================== //================================================================================================== void* util::memory::SharedMemoryTable::Allocate( size_t requested_size, const char* name, const int line_no) { size_t resized = BUF_ALIGN_008(requested_size); if (resized == 0) { // NOTE: f110708.6L, some of applications has internal memory check routine // that the size 0 test. for example, the DirectX 9.0c, 2006, Feb. version differ // after version. //assert(!"do you really want to require size 0 allocation?"); requested_size = 1; resized = BUF_ALIGN_008(1); }; void* allocated_ptr = NULL; if (resized <= this->kSizeOverUpperbound) { size_t index = (resized >> 3); if (const TokenSizeNode* pool_info = &this->index_by_size8x_[index]) { index = pool_info->pool_index; assert(pool_info->token_size == resized); }; if (SharedMemoryPoolSizeBased* pool = &this->size_pool_instance_[index]) { allocated_ptr = pool->Allocate(this, requested_size, name, line_no); }; #if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR if (__fnSharedMemoryLeakDetect) { __fnSharedMemoryLeakDetect(issued_ordered_number_); }; #endif } else { size_t block_size = sizeof(SharedMemoryPoolSizeBased::MemoryForUse) + BUF_ALIGN_008(requested_size) + sizeof(SharedMemoryPoolSizeBased::TokenVerifier); SharedMemoryPoolSizeBased::MemoryForUse* head_ptr = \ reinterpret_cast(::malloc(block_size)); if (head_ptr == NULL) { SUNLOG(eCRITICAL_LOG, "[%s:%d] malloc fail : %s, %d, size=%d", __FUNCTION__, __LINE__, name, line_no, requested_size); return NULL; } allocated_ptr = (uint8_t*)(head_ptr) + sizeof(*head_ptr); if (SharedMemoryPoolSizeBased::TokenVerifier* header = head_ptr->header) { header->parent = (SharedMemoryPoolSizeBased::Token*)(allocated_ptr); header->using_tag.composed = static_cast(requested_size); }; if (SharedMemoryPoolSizeBased::TokenVerifier* tail = reinterpret_cast( (uint8_t*)(allocated_ptr) + requested_size)) { *tail = *head_ptr->header; }; #if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR const bool huge_chunk = (1024 * 1024) < block_size; SharedMemoryPoolSizeBased::Statistics* statistic = NULL; if (huge_chunk) { size_t bound_index = BUF_1024x1024_IDX_BY_SIZE(block_size); if (bound_index < _countof(chunk_statistics_1024x1024)) { statistic = &chunk_statistics_1024x1024[bound_index]; } } else { size_t bound_index = BUF_4096_IDX_BY_SIZE(block_size); if (bound_index < _countof(chunk_statistics_4096)) { statistic = &chunk_statistics_4096[bound_index]; } }; if (statistic != NULL) { ++statistic->number_of_alloc_nodes; ++statistic->number_of_alloc_requested; }; #endif } if (allocated_ptr) { ++reference_counter_; if (reference_counter_ < 0) { SUNLOG(eCRITICAL_LOG, "[%s:%d] reference_counter_ overflow accured", __FUNCTION__, __LINE__); } }; return allocated_ptr; } void util::memory::SharedMemoryTable::Deallocate(void* element) { eCheckMemoryNodeResult result = util::memory::eError_NotDefined; SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use = \ SharedMemoryPoolSizeBased::CheckNodeHeader(element, &result); if (result == util::memory::eError_Success_PoolManagedToken) { size_t used_size = memory_for_use->header->using_tag.size; size_t resized = BUF_ALIGN_008(used_size); size_t index = (resized >> 3); ; index = this->index_by_size8x_[index].pool_index; SharedMemoryPoolSizeBased* const pool = &this->size_pool_instance_[index]; pool->Deallocate(this, memory_for_use); --reference_counter_; return; } else if (result == util::memory::eError_Success_PoolUnmanagedToken) { #if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR size_t block_size = memory_for_use->header->using_tag.composed; const bool huge_chunk = (1024 * 1024) < block_size; SharedMemoryPoolSizeBased::Statistics* statistic = NULL; if (huge_chunk) { size_t bound_index = BUF_1024x1024_IDX_BY_SIZE(block_size); if (bound_index < _countof(chunk_statistics_1024x1024)) { statistic = &chunk_statistics_1024x1024[bound_index]; } } else { size_t bound_index = BUF_4096_IDX_BY_SIZE(block_size); if (bound_index < _countof(chunk_statistics_4096)) { statistic = &chunk_statistics_4096[bound_index]; } }; if (statistic != NULL) { ++statistic->number_of_free_nodes; ++statistic->number_of_free_requested; }; #endif --reference_counter_; ::free(memory_for_use); return; } // error handling this->ReportRuntimeFailedObject(result, element, memory_for_use); __debugbreak(); } //================================================================================================== #define CALCULATE_PAGE_FIT_IN_INFO(__info__, __aligned_size__) #define SM_NODE_LIST() \ /* 8x based */ \ SM_NODE_DECL(kSizeIndex_0008, 8, 8, 5290) /* 124K*/ \ SM_NODE_DECL(kSizeIndex_0016, 16, 16, 4905) /* 128K*/ \ SM_NODE_DECL(kSizeIndex_0024, 24, 24, 3174) /* 124K*/ \ SM_NODE_DECL(kSizeIndex_0032, 32, 32, 2645) /* 124K*/ \ SM_NODE_DECL(kSizeIndex_0040, 40, 40, 146) /* 8K*/ \ SM_NODE_DECL(kSizeIndex_0048, 48, 48, 127) /* 8K*/ \ SM_NODE_DECL(kSizeIndex_0056, 56, 56, 56) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_0064, 64, 64, 51) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_0072, 72, 72, 46) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_0080, 80, 80, 213) /* 20K*/ \ SM_NODE_DECL(kSizeIndex_0088, 88, 88, 1142) /* 116K*/ \ SM_NODE_DECL(kSizeIndex_0096, 96, 96, 73) /* 8K*/ \ SM_NODE_DECL(kSizeIndex_0104, 104, 104, 34) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_0112, 112, 112, 31) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_0120, 120, 120, 30) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_0128, 128, 128, 28) /* 4K*/ \ /* 32x based */ \ SM_NODE_DECL(kSizeIndex_0160, 160, 160, 93) /* 16K*/ \ SM_NODE_DECL(kSizeIndex_0192, 192, 192, 315) /* 64K*/ \ SM_NODE_DECL(kSizeIndex_0224, 224, 224, 17) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_0256, 256, 256, 15) /* 4K*/ \ /* 64x based */ \ SM_NODE_DECL(kSizeIndex_0320, 320, 320, 12) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_0384, 384, 384, 10) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_0448, 448, 448, 8) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_0512, 512, 512, 7) /* 4K*/ \ /* 128x based */ \ SM_NODE_DECL(kSizeIndex_0640, 640, 640, 231) /* 148K*/ \ SM_NODE_DECL(kSizeIndex_0768, 768, 768, 5) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_0896, 896, 896, 4) /* 4K*/ \ SM_NODE_DECL(kSizeIndex_1024, 1024, 1024, 63) /* 64K*/ \ SM_NODE_DECL(kSizeIndex_1152, 1152, 1152, 7) /* 8K*/ \ SM_NODE_DECL(kSizeIndex_1280, 1280, 1280, 22) /* 28K*/ \ SM_NODE_DECL(kSizeIndex_1408, 1408, 1408, 23) /* 32K*/ //================================================================================================== util::memory::SharedMemoryTable::SharedMemoryTable() { //FitInPageInfo fitin_pageinfo; memset(padding0_, 0xFF, sizeof(padding0_)); memset(padding1_, 0xCC, sizeof(padding1_)); memset(padding2_, 0xCD, sizeof(padding2_)); ++issued_ordered_number_; ++reference_counter_; BOOST_STATIC_ASSERT(kStreamingSizeCounts < 256); BOOST_STATIC_ASSERT((BUF_ALIGN_008(0) == 0) && (BUF_ALIGN_008(1) == 8)); // NOTE: f110706.3L, create two private heaps to support 'TokenBlock' and 'memory token for use' // the reason of using each separated heap protect the unexpected status // of the 'memory token for use' like a buffer overrun. ;{ //this->handle_token_block_ = ::HeapCreate(0, 0, 0); //assert(handle_token_block_ != INVALID_HANDLE_VALUE); //this->handle_using_block_ = ::HeapCreate(0, 0, 0); //assert(handle_using_block_ != INVALID_HANDLE_VALUE); }; // start 0 size. for (size_t token_size = 0; token_size <= kSizeOverUpperbound; (token_size += 8)) { size_t array_index = (token_size >> 3); if (token_size <= kSize008xUpperbound) { size_t recalc_size = token_size - 0; index_by_size8x_[array_index].pool_index = static_cast(recalc_size >> 3); index_by_size8x_[array_index].token_size = static_cast(token_size); } else if (token_size <= kSize032xUpperbound) { size_t recalc_size = token_size - kSize008xUpperbound; index_by_size8x_[array_index].pool_index = static_cast(\ (recalc_size >> 5) + ((recalc_size & (32 - 1)) ? 1 : 0) + kSizeIndex_0128); index_by_size8x_[array_index].token_size = static_cast(token_size); } else if (token_size <= kSize064xUpperbound) { size_t recalc_size = token_size - kSize032xUpperbound; index_by_size8x_[array_index].pool_index = static_cast(\ (recalc_size >> 6) + ((recalc_size & (64 - 1)) ? 1 : 0) + kSizeIndex_0256); index_by_size8x_[array_index].token_size = static_cast(token_size); } else if (token_size <= kSize128xUpperbound) { size_t recalc_size = token_size - kSize064xUpperbound; index_by_size8x_[array_index].pool_index = static_cast(\ (recalc_size >> 7) + ((recalc_size & (128 - 1)) ? 1 : 0) + kSizeIndex_0512); index_by_size8x_[array_index].token_size = static_cast(token_size); } }; assert(*(ulong*)padding0_ == 0xFFFFFFFF); assert(*(ulong*)padding1_ == 0xCCCCCCCC); assert(*(ulong*)padding2_ == 0xCDCDCDCD); // //---------------------------------------------------------------------------------------------- if (util::memory::SharedMemoryPoolSizeBased* pool = &this->size_pool_instance_[kSizeIndex_None]) { // nothing to do }; #undef SM_NODE_DECL #define SM_NODE_DECL(_size_index_, _byte_alignment_size_, _dummy_, _growth_) \ if (util::memory::SharedMemoryPoolSizeBased* pool = &this->size_pool_instance_[_size_index_]) \ { \ CALCULATE_PAGE_FIT_IN_INFO(&fitin_pageinfo, (_byte_alignment_size_)); \ new (pool) util::memory::SharedMemoryPoolSizeBased((_byte_alignment_size_), (_growth_)); \ }; //---------------------------------------------------------------------------------------------- SM_NODE_LIST(); // instance //---------------------------------------------------------------------------------------------- this->initialized_ = true; } util::memory::SharedMemoryTable::~SharedMemoryTable() { this->initialized_ = false; #undef SM_NODE_DECL #define SM_NODE_DECL(_size_index_, _byte_alignment_size_, _dummy_, _growth_) \ if (util::memory::SharedMemoryPoolSizeBased* pool = &this->size_pool_instance_[_size_index_]) \ { \ pool->FreeAllElements(this); \ }; //---------------------------------------------------------------------------------------------- SM_NODE_LIST(); // release //---------------------------------------------------------------------------------------------- //if (this->handle_token_block_ != INVALID_HANDLE_VALUE) { // ::HeapDestroy(this->handle_token_block_); // this->handle_token_block_ = INVALID_HANDLE_VALUE; //}; //if (this->handle_using_block_ != INVALID_HANDLE_VALUE) { // ::HeapDestroy(this->handle_using_block_); // this->handle_using_block_ = INVALID_HANDLE_VALUE; //}; } //================================================================================================== void _SetSharedMemoryLeakDetect(void (*userhook)(DWORD)) { #if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR __fnSharedMemoryLeakDetect = userhook; return; #else __UNUSED(userhook); #endif } void TestUnit_UsedLogOutput() { #if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR if (SharedMemoryPool::CheckInstanced() == false) { return; }; SharedMemoryPool* shared_memory_pool = SMPOOL_PTR(); SMROUTER_PTR(shared_memory_pool)->ReportCurrentMemoryUsages(); return; #endif // } BOOL TraceShareMemoryLeak(const char* const path_file_name) { #if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR if (SharedMemoryPool::CheckInstanced() == false) { util::memory::SharedMemoryTable::TouchMemoryLeakReportFile(path_file_name); return true; }; SharedMemoryPool* shared_memory_pool = SMPOOL_PTR(); return SMROUTER_PTR(shared_memory_pool)->ReportMemoryLeaks(path_file_name); // #else __UNUSED(path_file_name); return true; #endif } void util::memory::SharedMemoryTable::ReportRuntimeFailedObject(eCheckMemoryNodeResult error, void* ptr, SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use) { #if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR switch (error) { case util::memory::eError_NotDefined: ASSERT(!"unexpected error"); return; case util::memory::eError_Success_PoolManagedToken: case util::memory::eError_Success_PoolUnmanagedToken: ASSERT(!"can't entered with this result"); return; case util::memory::eError_Fail_Null_Pointer: ASSERT(!"requested null pointer releasing"); return; }; SharedMemoryPoolSizeBased::UsingTag verifier = memory_for_use->header->using_tag; uint8_t* used_ptr = reinterpret_cast(ptr); if ((error != util::memory::eError_Fail_BufferOverrunedToken) || (void*)memory_for_use->header->parent == used_ptr) { SUNLOG(eCRITICAL_LOG, _T("|MemoryCheckReport|斤口=token validation error logging#1, Error(%d)") _T("|MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)") _T("|Dump=") _T("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X|"), error, memory_for_use, verifier.size, (verifier.tag & 0xFF), ((verifier.tag >> 8) & 0xFF), *(ulong*)memory_for_use, used_ptr[ 0], used_ptr[ 1], used_ptr[ 2], used_ptr[ 3], used_ptr[ 4], used_ptr[ 5], used_ptr[ 6], used_ptr[ 7], used_ptr[ 8], used_ptr[ 9], used_ptr[10], used_ptr[11], used_ptr[12], used_ptr[13], used_ptr[14], used_ptr[15]); } else { util::memory::SharedMemoryPoolSizeBased::Token* const token = memory_for_use->header->parent; // ... dangerous... SUNLOG(eCRITICAL_LOG, _T("|MemoryCheckReport|斤口=token validation error logging#2, Error(%d)") _T("|MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)") _T("|Location='%s', %d lines|ExtraMsg='%s'") _T("|Dump=") _T("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X|"), error, used_ptr, token->using_tag.size, (token->using_tag.tag & 0xFF), ((token->using_tag.tag >> 8) & 0xFF), *(ulong*)used_ptr, token->function, token->line_no, "suspicious buffer overrun object", used_ptr[ 0], used_ptr[ 1], used_ptr[ 2], used_ptr[ 3], used_ptr[ 4], used_ptr[ 5], used_ptr[ 6], used_ptr[ 7], used_ptr[ 8], used_ptr[ 9], used_ptr[10], used_ptr[11], used_ptr[12], used_ptr[13], used_ptr[14], used_ptr[15]); } assert(!"corrupted!"); return; #else __UNUSED((error, ptr, memory_for_use)); return; #endif } void util::memory::SharedMemoryTable::TouchMemoryLeakReportFile(const char* path_file_name) { #if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR HANDLE file_handle = ::CreateFile(path_file_name, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file_handle == INVALID_HANDLE_VALUE) { return; }; ::CloseHandle(file_handle); return; #else __UNUSED(path_file_name); return; #endif } bool util::memory::SharedMemoryTable::ReportMemoryLeaks(const char* path_file_name) { #if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR const int kMaxOutputCounter = 100; if (this->initialized_ == false) { return true; // already free. }; #if defined(_SERVER) HANDLE file_handle = ::CreateFile(path_file_name, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file_handle == INVALID_HANDLE_VALUE) { return false; }; #endif // char buffer[4096]; DWORD file_written = 0; int written = 0; __TOUCHED((path_file_name, file_written)); SharedMemoryPoolSizeBased* pool_it = &this->size_pool_instance_[1]; // 0 is unused const SharedMemoryPoolSizeBased* const pool_end = &this->size_pool_instance_[_countof(this->size_pool_instance_)]; for (int counter = 0; pool_it != pool_end; ++pool_it) { util::__LList* const token_end = &pool_it->alloc_list_; SharedMemoryPoolSizeBased::Token* token_it = pool_it->alloc_list_.next; for (; token_it != token_end; token_it = token_it->next) { if (counter >= kMaxOutputCounter) { buffer[written++] = '/'; buffer[written++] = '/'; }; // SharedMemoryPoolSizeBased::MemoryForUse* const memory_for_use = token_it->link; ulong* const used_ptr = reinterpret_cast(memory_for_use + 1); uint8_t* const used_ptr_dump = reinterpret_cast(used_ptr); SharedMemoryPoolSizeBased::TokenVerifier tail_tag = \ *reinterpret_cast( used_ptr_dump + token_it->using_tag.size); tail_tag.using_tag.tag -= SharedMemoryPoolSizeBased::kMagicCodeTailConv; const bool matched_link = (token_it == memory_for_use->header->parent); const bool matched_headtag = (token_it->using_tag.composed == memory_for_use->header->using_tag.composed); const bool matched_tail = (token_it == tail_tag.parent) && (token_it->using_tag.composed == tail_tag.using_tag.composed); if ((matched_headtag) && (matched_link) && (matched_tail)) { // 000 written += _snprintf(&buffer[written], _countof(buffer) - written, " case %8u: // |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|" "Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg=(none)\r\n", token_it->issued_number, used_ptr, token_it->using_tag.size, (token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF), *used_ptr, token_it->function, token_it->line_no, used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3]); ++counter; } else if ((matched_headtag) && (matched_link) && (!matched_tail)) { // 001 written += _snprintf(&buffer[written], _countof(buffer) - written, " case %8u: // |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|" "Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n", token_it->issued_number, used_ptr, token_it->using_tag.size, (token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF), *used_ptr, token_it->function, token_it->line_no, used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3], "suspicious buffer overrun object"); ++counter; } else if ((matched_headtag) && (!matched_link) && (matched_tail)) { // 010 -- very rarely written += _snprintf(&buffer[written], _countof(buffer) - written, "// case %8u: |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|" "Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n", token_it->issued_number, used_ptr, token_it->using_tag.size, (token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF), *used_ptr, token_it->function, token_it->line_no, used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3], "corrupted"); } else if ((matched_headtag) && (!matched_link) && (!matched_tail)) { // 011 -- very rarely written += _snprintf(&buffer[written], _countof(buffer) - written, " case %8u: // |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|" "Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n", token_it->issued_number, used_ptr, token_it->using_tag.size, (token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF), *used_ptr, token_it->function, token_it->line_no, used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3], "corrupted & overruned"); ++counter; } else if ((!matched_headtag) && (matched_link) && (matched_tail)) { // 100 -- rarely written += _snprintf(&buffer[written], _countof(buffer) - written, " case %8u: // |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|" "Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n", token_it->issued_number, used_ptr, token_it->using_tag.size, (token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF), *used_ptr, token_it->function, token_it->line_no, used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3], "may be overruned by previous token"); ++counter; } else if ((!matched_headtag) && (matched_link) && (!matched_tail)) { // 101 -- vary rarely written += _snprintf(&buffer[written], _countof(buffer) - written, " case %8u: // |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|" "Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n", token_it->issued_number, used_ptr, token_it->using_tag.size, (token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF), *used_ptr, token_it->function, token_it->line_no, used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3], "may be overruned by previous token and overruned"); ++counter; } else if ((!matched_headtag) && (!matched_link) && (matched_tail)) { // 110 -- rarely written += _snprintf(&buffer[written], _countof(buffer) - written, "// case %8u: |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|" "Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n", token_it->issued_number, used_ptr, token_it->using_tag.size, (token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF), *used_ptr, token_it->function, token_it->line_no, used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3], "may be overruned by previous token"); } else if ((!matched_headtag) && (!matched_link) && (!matched_tail)) { // 111 -- rarely written += _snprintf(&buffer[written], _countof(buffer) - written, "// case %8u: |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|" "Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n", token_it->issued_number, used_ptr, token_it->using_tag.size, (token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF), *used_ptr, token_it->function, token_it->line_no, used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3], "may be overruned by previous token, fully overruned"); } // #if defined(_SERVER) ::WriteFile(file_handle, buffer, written, &file_written, NULL); #else OutputDebugString(buffer); #endif written = 0; // }; }; #if defined(_SERVER) ::FlushFileBuffers(file_handle); ::CloseHandle(file_handle); #endif return true; #else // !USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR __UNUSED(path_file_name); return true; #endif // } bool util::memory::SharedMemoryTable::ReportCurrentMemoryUsages() { #if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR if (this->initialized_ == false) { return true; // already free. }; HANDLE file_handle = ::CreateFile("./memory_usage.log", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file_handle == INVALID_HANDLE_VALUE) { return false; }; // char buffer[32768]; int written = 0; SharedMemoryPoolSizeBased* pool_it = &this->size_pool_instance_[1]; // 0 is unused const SharedMemoryPoolSizeBased* const pool_end = &this->size_pool_instance_[_countof(this->size_pool_instance_)]; for (/*int counter = 0*/; pool_it != pool_end; ++pool_it) { const SharedMemoryPoolSizeBased::Statistics& statistics = pool_it->statistics_; written += _snprintf(&buffer[written], _countof(buffer) - written, "|TokenSize=[%4u]|TotalTokens=%8u" "|NumberOfAllocated=%8u|NumberOfFreed=%8u" "|NumberOfAllocRequest=%8u|NumberOfFreeRequest=%8u|\r\n", pool_it->type_size_, statistics.number_of_total_blocks * pool_it->growth_count_, statistics.number_of_alloc_nodes, statistics.number_of_free_nodes, statistics.number_of_alloc_requested, statistics.number_of_free_requested); }; DWORD file_written = 0; ::WriteFile(file_handle, buffer, written, &file_written, NULL); // ;{ written = 0; const SharedMemoryPoolSizeBased::Statistics* non_pool_it = this->chunk_statistics_4096, * const non_pool_end = &this->chunk_statistics_4096[_countof(this->chunk_statistics_4096)]; for (; non_pool_it != non_pool_end; ++non_pool_it) { written += _snprintf(&buffer[written], _countof(buffer) - written, "|NonPool|MaxSize=[%2uKBytes]|" "|NumberOfAllocated=%8u|NumberOfFreed=%8u" "|NumberOfAllocRequest=%8u|NumberOfFreeRequest=%8u|\r\n", ((static_cast(non_pool_it - this->chunk_statistics_4096) + 1) * 4), non_pool_it->number_of_alloc_nodes, non_pool_it->number_of_free_nodes, non_pool_it->number_of_alloc_requested, non_pool_it->number_of_free_requested); } ::WriteFile(file_handle, buffer, written, &file_written, NULL); }; ;{ written = 0; const SharedMemoryPoolSizeBased::Statistics* non_pool_it = this->chunk_statistics_1024x1024, * const non_pool_end = &this->chunk_statistics_1024x1024[\ _countof(this->chunk_statistics_1024x1024)]; for (; non_pool_it != non_pool_end; ++non_pool_it) { written += _snprintf(&buffer[written], _countof(buffer) - written, "|NonPool|MaxSize=[%2uMBytes]|" "|NumberOfAllocated=%8u|NumberOfFreed=%8u" "|NumberOfAllocRequest=%8u|NumberOfFreeRequest=%8u|\r\n", (static_cast(non_pool_it - this->chunk_statistics_1024x1024) + 1), non_pool_it->number_of_alloc_nodes, non_pool_it->number_of_free_nodes, non_pool_it->number_of_alloc_requested, non_pool_it->number_of_free_requested); } ::WriteFile(file_handle, buffer, written, &file_written, NULL); }; ::FlushFileBuffers(file_handle); ::CloseHandle(file_handle); return true; #else return true; #endif }