diff --git a/sakura/sakura.vcxproj b/sakura/sakura.vcxproj index 64e3ee05f6..67c3cfcb84 100644 --- a/sakura/sakura.vcxproj +++ b/sakura/sakura.vcxproj @@ -438,6 +438,7 @@ + diff --git a/sakura/sakura.vcxproj.filters b/sakura/sakura.vcxproj.filters index 776fce9f4e..a67d061dcb 100644 --- a/sakura/sakura.vcxproj.filters +++ b/sakura/sakura.vcxproj.filters @@ -1088,6 +1088,9 @@ Cpp Source Files\recent + + Cpp Source Files\mem + diff --git a/sakura_core/doc/layout/CLayoutMgr.cpp b/sakura_core/doc/layout/CLayoutMgr.cpp index bb792180a2..9e58d7b0b4 100644 --- a/sakura_core/doc/layout/CLayoutMgr.cpp +++ b/sakura_core/doc/layout/CLayoutMgr.cpp @@ -25,6 +25,7 @@ #include "charset/charcode.h" #include "mem/CMemory.h"/// 2002/2/10 aroka #include "mem/CMemoryIterator.h" // 2006.07.29 genta +#include "mem/CPoolResource.h" #include "view/CViewFont.h" #include "view/CTextMetrics.h" #include "basis/SakuraBasis.h" @@ -37,6 +38,8 @@ CLayoutMgr::CLayoutMgr() : m_getIndentOffset( &CLayoutMgr::getIndentOffset_Normal ) // Oct. 1, 2002 genta // Nov. 16, 2002 メンバー関数ポインタにはクラス名が必要 + , m_layoutMemRes(new CPoolResource()) + //, m_layoutMemRes(new std::pmr::unsynchronized_pool_resource()) // メモリ使用量が大きい為に使用しない { m_pcDocLineMgr = NULL; m_pTypeConfig = NULL; @@ -95,7 +98,8 @@ void CLayoutMgr::_Empty() CLayout* pLayout = m_pLayoutTop; while( pLayout ){ CLayout* pLayoutNext = pLayout->GetNextLayout(); - delete pLayout; + pLayout->~CLayout(); + m_layoutMemRes->deallocate(pLayout, sizeof(CLayout), alignof(CLayout)); pLayout = pLayoutNext; } } @@ -381,7 +385,7 @@ CLayout* CLayoutMgr::CreateLayout( CLayoutColorInfo* colorInfo ) { - CLayout* pLayout = new CLayout( + CLayout* pLayout = new (m_layoutMemRes->allocate(sizeof(CLayout))) CLayout( pCDocLine, ptLogicPos, nLength, @@ -589,7 +593,8 @@ CLayout* CLayoutMgr::DeleteLayoutAsLogical( DEBUG_TRACE( _T("バグバグ\n") ); } - delete pLayout; + pLayout->~CLayout(); + m_layoutMemRes->deallocate(pLayout, sizeof(CLayout), alignof(CLayout)); m_nLines--; /* 全物理行数 */ if( NULL == pLayoutNext ){ diff --git a/sakura_core/doc/layout/CLayoutMgr.h b/sakura_core/doc/layout/CLayoutMgr.h index cfc03ad079..2c9524ef3c 100644 --- a/sakura_core/doc/layout/CLayoutMgr.h +++ b/sakura_core/doc/layout/CLayoutMgr.h @@ -24,6 +24,7 @@ #include // 2002/2/10 aroka #include +#include #include "doc/CDocListener.h" #include "_main/global.h"// 2002/2/10 aroka #include "basis/SakuraBasis.h" @@ -399,6 +400,7 @@ class CLayoutMgr : public CProgressSubject //実データ CLayout* m_pLayoutTop; CLayout* m_pLayoutBot; + std::unique_ptr m_layoutMemRes; //タイプ別設定 const STypeConfig* m_pTypeConfig; diff --git a/sakura_core/doc/logic/CDocLineMgr.cpp b/sakura_core/doc/logic/CDocLineMgr.cpp index 0b5db9a200..39aafea884 100644 --- a/sakura_core/doc/logic/CDocLineMgr.cpp +++ b/sakura_core/doc/logic/CDocLineMgr.cpp @@ -38,6 +38,7 @@ // May 15, 2000 genta #include "CEol.h" #include "mem/CMemory.h"// 2002/2/10 aroka +#include "mem/CPoolResource.h" #include "io/CFileLoad.h" // 2002/08/30 Moca #include "io/CIoBridge.h" @@ -52,6 +53,8 @@ // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- // CDocLineMgr::CDocLineMgr() + : m_docLineMemRes(new CPoolResource()) + //: m_docLineMemRes(new std::pmr::unsynchronized_pool_resource()) // メモリ使用量が大きい為に使用しない { _Init(); } @@ -68,7 +71,7 @@ CDocLineMgr::~CDocLineMgr() //! pPosの直前に新しい行を挿入 CDocLine* CDocLineMgr::InsertNewLine(CDocLine* pPos) { - CDocLine* pcDocLineNew = new CDocLine; + CDocLine* pcDocLineNew = new (m_docLineMemRes->allocate(sizeof(CDocLine))) CDocLine(); _InsertBeforePos(pcDocLineNew,pPos); return pcDocLineNew; } @@ -76,7 +79,7 @@ CDocLine* CDocLineMgr::InsertNewLine(CDocLine* pPos) //! 最下部に新しい行を挿入 CDocLine* CDocLineMgr::AddNewLine() { - CDocLine* pcDocLineNew = new CDocLine; + CDocLine* pcDocLineNew = new (m_docLineMemRes->allocate(sizeof(CDocLine))) CDocLine(); _PushBottom(pcDocLineNew); return pcDocLineNew; } @@ -87,7 +90,8 @@ void CDocLineMgr::DeleteAllLine() CDocLine* pDocLine = m_pDocLineTop; while( pDocLine ){ CDocLine* pDocLineNext = pDocLine->GetNextLine(); - delete pDocLine; + pDocLine->~CDocLine(); + m_docLineMemRes->deallocate(pDocLine, sizeof(CDocLine)); pDocLine = pDocLineNext; } _Init(); @@ -118,7 +122,8 @@ void CDocLineMgr::DeleteLine( CDocLine* pcDocLineDel ) } //データ削除 - delete pcDocLineDel; + pcDocLineDel->~CDocLine(); + m_docLineMemRes->deallocate(pcDocLineDel, sizeof(CDocLine)); //行数減算 m_nLines--; diff --git a/sakura_core/doc/logic/CDocLineMgr.h b/sakura_core/doc/logic/CDocLineMgr.h index 1f9622a198..819dce8ef5 100644 --- a/sakura_core/doc/logic/CDocLineMgr.h +++ b/sakura_core/doc/logic/CDocLineMgr.h @@ -21,12 +21,13 @@ #define _CDOCLINEMGR_H_ #include +#include #include "_main/global.h" // 2002/2/10 aroka #include "basis/SakuraBasis.h" #include "util/design_template.h" #include "COpe.h" +#include "CDocLine.h" -class CDocLine; // 2002/2/10 aroka class CBregexp; // 2002/2/10 aroka struct DocLineReplaceArg { @@ -89,6 +90,7 @@ class CDocLineMgr{ CDocLine* m_pDocLineTop; //!< 最初の行 CDocLine* m_pDocLineBot; //!< 最後の行(※1行しかない場合はm_pDocLineTopと等しくなる) CLogicInt m_nLines; //!< 全行数 + std::unique_ptr m_docLineMemRes; public: //$$ kobake注: 以下、絶対に切り離したい(最低切り離せなくても、変数の意味をコメントで明確に記すべき)変数群 diff --git a/sakura_core/mem/CPoolResource.h b/sakura_core/mem/CPoolResource.h new file mode 100644 index 0000000000..29fb4a1829 --- /dev/null +++ b/sakura_core/mem/CPoolResource.h @@ -0,0 +1,137 @@ +/* + Copyright (C) 2018-2019 Sakura Editor Organization + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment + in the product documentation would be appreciated but is + not required. + + 2. Altered source versions must be plainly marked as such, + and must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef SAKURA_CPOOLRESOURCE_H_ +#define SAKURA_CPOOLRESOURCE_H_ + +#include +#include + +// std::pmr::unsynchronized_pool_resource だとメモリ使用量が大きい為、自前実装を用意 +// T : 要素型 +template +class CPoolResource : public std::pmr::memory_resource +{ +public: + CPoolResource() + { + // 始めのブロックをメモリ確保 + AllocateBlock(); + } + + virtual ~CPoolResource() + { + // メモリ確保した領域の連結リストを辿って全てのブロック分のメモリ解放 + Node* curr = m_currentBlock; + while (curr) { + Node* next = curr->next; + VirtualFree(curr, 0, MEM_RELEASE); + curr = next; + } + } + +protected: + // 要素のメモリ確保処理、要素の領域のポインタを返す + // bytes と alignment 引数は使用しない、template 引数の型で静的に決定する + void* do_allocate([[maybe_unused]] std::size_t bytes, + [[maybe_unused]] std::size_t alignment) override + { + // メモリ確保時には未割当領域から使用していく + if (m_unassignedNode) { + T* ret = reinterpret_cast(m_unassignedNode); + m_unassignedNode = m_unassignedNode->next; + return ret; + } + else { + // 未割当領域が無い場合は、ブロックの中から切り出す + // 現在のブロックに新規確保するNodeサイズ分の領域が余っていない場合は新規のブロックを確保 + Node* blockEnd = reinterpret_cast(reinterpret_cast(m_currentBlock) + BlockSize); + if (m_currentNode + 1 >= blockEnd) { + AllocateBlock(); + } + // 要素の領域のポインタを返すと同時にポインタを次に進めて切り出す位置を更新する + return reinterpret_cast(m_currentNode++); + } + } + + // メモリ解放処理、要素の領域のポインタを受け取る + // 第1引数には、do_allocate メソッドで返したポインタを渡す事 + // bytes と alignment 引数は使用しない、template 引数の型で静的に決定する + void do_deallocate(void* p, + [[maybe_unused]] std::size_t bytes, + [[maybe_unused]] std::size_t alignment) override + { + if (p) { + // メモリ解放した領域を未割当領域として自己参照共用体の片方向連結リストで繋げる + // 次回のメモリ確保時にその領域を再利用する + Node* next = m_unassignedNode; + m_unassignedNode = reinterpret_cast(p); + m_unassignedNode->next = next; + } + } + + bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override + { + return this == &other; + } + +private: + static constexpr size_t BlockSize = 1024 * 64; // VirtualAlloc を使用する為このサイズ + + // 共用体を使う事で要素型と自己参照用のポインタを同じ領域に割り当てる + // 共用体のサイズは各メンバを格納できるサイズになる事を利用する + union Node { + ~Node() {} + T element; // 要素型 + Node* next; // ブロックのヘッダの場合は、次のブロックに繋がる + // 解放後の未割当領域の場合は次の未割当領域に繋がる + }; + + static_assert(2 * sizeof(Node) <= BlockSize, "sizeof(T) too big."); + + // 呼び出しの度にメモリの動的確保を細かく行う事を避ける為に、一括でブロック領域を確保 + // ブロックの先頭(head)にはブロックの連結用のポインタが配置され、残る領域(body)には要素が記録される + void AllocateBlock() + { + char* buff = reinterpret_cast(VirtualAlloc(NULL, BlockSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + if (!buff) throw std::bad_alloc(); + Node* next = m_currentBlock; + // ブロック領域の先頭(head)はNodeのポインタとして扱い、以前に作成したブロックに連結する + m_currentBlock = reinterpret_cast(buff); + m_currentBlock->next = next; + + // ブロック領域の残る部分は要素の領域とするが、アライメントを取る + void* body = buff + sizeof(Node*); + size_t space = BlockSize - sizeof(Node*); + body = std::align(alignof(Node), sizeof(Node), body, space); + assert(body); + m_currentNode = reinterpret_cast(body); + } + + Node* m_unassignedNode = nullptr; // 未割当領域の先頭 + Node* m_currentBlock = nullptr; // 現在のブロック + Node* m_currentNode = nullptr; // 要素確保処理時に現在のブロックの中から切り出すNodeを指すポインタ、メモリ確保時に未割当領域が無い場合はここを使う +}; + +#endif /* SAKURA_CPOOLRESOURCE_H_ */