首页 > 技术文章 > MultilingualSimpleObject

hgwang 2021-02-23 20:12 原文

  1 //
  2 // Created by whg on 2020/8/25.
  3 //
  4 #pragma once
  5 #include <utility>
  6 #include <memory>
  7 #include <vector>
  8 #include <chrono>
  9 
 10 namespace typany {
 11 namespace ObjectPool {
 12 
 13     inline int64_t GetCurrentTimeStamp() {
 14         std::chrono::time_point<std::chrono::system_clock> current = std::chrono::system_clock::now();
 15         auto stamp = std::chrono::duration_cast<std::chrono::milliseconds>(current.time_since_epoch());
 16         return stamp.count();
 17     }
 18 
 19     template <typename T, size_t ChunkMaxBlockSize = 128, std::int64_t MaxAccessIntervalMillisecond = 3*60*1000>
 20     class Allocator
 21     {
 22     public:
 23         typedef T               value_type;
 24         typedef T*              pointer;
 25         typedef const T*        const_pointer;
 26 
 27     private:
 28         Allocator() {}
 29         ~Allocator(){
 30             Chunk* chunkPointer = chunk_;
 31             while (chunkPointer != nullptr) {
 32                 Chunk* next = chunkPointer->Next();
 33                 ::delete chunkPointer;
 34                 chunkPointer = next;
 35             }
 36         }
 37 
 38     public:
 39         static Allocator<value_type>& Instance() {
 40             static Allocator<value_type> allocator_;
 41             return allocator_;
 42         }
 43         void* Allocate(size_t size) {
 44             if (size > MaxSize()) {
 45                 throw std::runtime_error("");
 46             }
 47 
 48             if (chunk_ == nullptr) {
 49                 chunk_ = ::new Chunk(ChunkMaxBlockSize, minBlockSize_, align_);
 50             }
 51 
 52             Chunk* chunkPointer = chunk_;
 53             while (chunkPointer != nullptr) {
 54                 if (!chunkPointer->Full() || chunkPointer->Next() == nullptr) {
 55                     break;
 56                 }
 57                 chunkPointer = chunkPointer->Next();
 58             }
 59             if (!chunkPointer->Full()) {
 60                 return chunkPointer->Acquire();
 61             }
 62             if (chunkPointer->Next() == nullptr) {
 63                 chunkPointer->Next(::new Chunk(ChunkMaxBlockSize, minBlockSize_, align_));
 64             }
 65             return chunkPointer->Next()->Acquire();
 66         }
 67 
 68         void Deallocate(void* ptr, size_t length) noexcept {
 69             if (chunk_ == nullptr) {
 70                 throw std::runtime_error("Allocator<T>::allocate(size_t n) 'n' exceeds maximum supported size");
 71             }
 72 
 73             Chunk* chunkPointer = chunk_;
 74             while (chunkPointer != nullptr) {
 75                 if (chunkPointer->InRange(ptr) || chunkPointer->Next() == nullptr) {
 76                     break;
 77                 }
 78                 chunkPointer = chunkPointer->Next();
 79             }
 80             if (chunkPointer->InRange(ptr) && chunkPointer->CheckAddressValid(ptr)) {
 81                 chunkPointer->Release(ptr);
 82             } else {
 83                 throw std::runtime_error("Allocator<T>::allocate(size_t n) 'n' exceeds maximum supported size");
 84             }
 85 
 86             ++deallocateCount_;
 87             ShrinkChunk();
 88         }
 89         inline size_t MaxSize() const noexcept {
 90             return size_t(~0) / type_size_;
 91         }
 92 
 93     private:
 94         // 收缩,超出MaxAccessIntervalMillisecond未访问,且Empty = true,则删掉该Chunk
 95         void ShrinkChunk() {
 96             if (chunk_ == nullptr || deallocateCount_ % ChunkMaxBlockSize != 0) {
 97                 return;
 98             }
 99             // 至少保留一个chunk
100             Chunk* chunkPointer = chunk_;
101             while (chunkPointer != nullptr) {
102                 Chunk* next = chunkPointer->Next();
103                 if (next == nullptr) {
104                     break;
105                 }
106                 if (next->Idle()) {
107                     std::int64_t chunkStamp = next->LastReleaseTimeStamp();
108                     std::int64_t currentStamp = GetCurrentTimeStamp();
109                     if (currentStamp - chunkStamp >= MaxAccessIntervalMillisecond) {
110                         chunkPointer->Next(next->Next());
111                         ::delete next;
112                     } else {
113                         chunkPointer = chunkPointer->Next();
114                     }
115                 } else {
116                     chunkPointer = chunkPointer->Next();
117                 }
118             }
119         }
120     private:
121         // 数据块,
122         class Chunk {
123         public:
124             Chunk(size_t maxBlockCount, size_t blockSize, size_t align) : maxBlockCount_(maxBlockCount), blockSize_(blockSize), length_(maxBlockCount_*blockSize_), align_(align) {
125                 unsigned char* address = (unsigned char*)malloc(length_);
126                 data_ = reinterpret_cast<pointer>(address);
127                 enabled_ = (data_ != nullptr);
128                 if (enabled_) {
129                     idle_.reserve(maxBlockCount_);
130                     for (size_t i = 0; i < maxBlockCount; ++i) {
131                         idle_.push_back(i);
132                     }
133                 }
134             }
135             ~Chunk(){
136                 Destory();
137             }
138             void* Acquire() {
139                 if (!enabled_ || Full()) {
140                     return nullptr;
141                 }
142                 size_t index = idle_.back();
143                 idle_.pop_back();
144                 lastReleaseTimeStamp_ = std::numeric_limits<std::int64_t>::max();
145                 return IndexToAddress(index);
146             }
147             void Release(void* ptr) {
148                 if (!InRange(ptr) || !CheckAddressValid(ptr)) {
149                     return;
150                 }
151                 size_t index = AddressToIndex(ptr);
152                 idle_.push_back(index);
153                 if (Idle()) {
154                     // 只记最后一次归还的时间
155                     lastReleaseTimeStamp_ = GetCurrentTimeStamp();
156                 }
157             }
158             void Destory() {
159                 if (!enabled_) {
160                     return;
161                 }
162                 free(data_);
163                 idle_.clear();
164             }
165             bool Full() const {
166                 return data_ == nullptr ? true : idle_.empty();
167             }
168             bool Idle() const {
169                 return idle_.size() == ChunkMaxBlockSize;
170             }
171             const_pointer Begin() const {
172                 return data_;
173             }
174             pointer End() const {
175                 return data_ + maxBlockCount_;
176             }
177             bool InRange(void* ptr) {
178                 return (data_ <= reinterpret_cast<pointer>(ptr) && reinterpret_cast<pointer>(ptr) < data_ + maxBlockCount_);
179             }
180             bool CheckAddressValid(void* ptr) {
181                 return (reinterpret_cast<size_t >(ptr) % align_ == 0)
182                        && ((reinterpret_cast<size_t >(ptr) - reinterpret_cast<size_t >(data_)) % blockSize_ == 0);
183             }
184             Chunk* Next() {
185                 return next_;
186             }
187             void Next(Chunk* chunkPointer) {
188                 next_ = chunkPointer;
189             }
190             const std::int64_t& LastReleaseTimeStamp() {
191                 return lastReleaseTimeStamp_;
192             }
193         private:
194             size_t AddressToIndex (void* ptr) {
195                 return reinterpret_cast<pointer>(ptr) - data_ ;
196             }
197             void* IndexToAddress(const size_t& index) {
198                 if (data_ == nullptr || index >= maxBlockCount_) {
199                     return nullptr;
200                 }
201                 return data_ + index;
202             }
203         private:
204             bool enabled_{false};
205             pointer data_{nullptr};
206             std::vector<size_t> idle_;
207             size_t maxBlockCount_{0};
208             size_t blockSize_{0};
209             size_t length_{0};
210             size_t align_{0};
211             std::int64_t lastReleaseTimeStamp_{std::numeric_limits<std::int64_t>::max()};
212         private:
213             Chunk* next_{nullptr};
214         };
215     private:
216         const size_t type_size_{sizeof(value_type)};
217         const size_t align_{alignof(value_type)};
218         const size_t minBlockSize_ {(sizeof(value_type) + alignof(value_type) - 1) / alignof(value_type) * alignof(value_type)};
219         size_t deallocateCount_{0};
220         Chunk* chunk_{nullptr};
221     };
222 
223     // 简易对象
224     template<typename ClassName>
225     class MultilingualSimpleObject : public ClassName
226     {
227         // 不要使用虚函数,虚表会增加内存开销
228         // 不要定义成员变量
229         typedef MultilingualSimpleObject<ClassName> BuiltInClass;
230     public:
231         template<typename... T>
232         MultilingualSimpleObject(T&&... t) : ClassName(std::forward<T>(t)...) {}
233 //        virtual ~MultilingualSimpleObject(){}
234 
235         template<typename... T>
236         static std::shared_ptr<ClassName> Create(T&&... t) {
237             return std::shared_ptr<ClassName>(new BuiltInClass(t...));
238         }
239 
240         static void* operator new(size_t size) {
241             return Allocator<BuiltInClass>::Instance().Allocate(1);
242         }
243 
244         static void operator delete (void* ptr, size_t size) {
245             Allocator<BuiltInClass>::Instance().Deallocate(ptr, size);
246         }
247     };
248 
249 }
250 }

 

推荐阅读