source: trunk/Mars/mcore/MemoryManager.h@ 17251

Last change on this file since 17251 was 17251, checked in by tbretz, 11 years ago
Forgot the #endif
File size: 4.3 KB
Line 
1#include <forward_list>
2
3class MemoryStock
4{
5 friend class MemoryChunk;
6 friend class MemoryManager;
7
8 size_t fChunkSize;
9 size_t fMaxMemory;
10
11 size_t fInUse;
12 size_t fAllocated;
13
14 size_t fMaxInUse;
15
16 std::mutex fMutexMem;
17 std::mutex fMutexCond;
18 std::condition_variable fCond;
19
20 std::forward_list<std::shared_ptr<char>> fMemoryStock;
21
22public:
23 MemoryStock(size_t chunk, size_t max) : fChunkSize(chunk), fMaxMemory(max<chunk?chunk:max),
24 fInUse(0), fAllocated(0), fMaxInUse(0)
25 {
26 }
27
28private:
29 std::shared_ptr<char> pop(bool block)
30 {
31 if (block)
32 {
33 // No free slot available, next alloc would exceed max memory:
34 // block until a slot is available
35 std::unique_lock<std::mutex> lock(fMutexCond);
36 while (fMemoryStock.empty() && fAllocated+fChunkSize>fMaxMemory)
37 fCond.wait(lock);
38 }
39 else
40 {
41 // No free slot available, next alloc would exceed max memory
42 // return an empty pointer
43 if (fMemoryStock.empty() && fAllocated+fChunkSize>fMaxMemory)
44 return std::shared_ptr<char>();
45 }
46
47 // We will return this amount of memory
48 // This is not 100% thread safe, but it is not a super accurate measure anyway
49 fInUse += fChunkSize;
50 if (fInUse>fMaxInUse)
51 fMaxInUse = fInUse;
52
53 if (fMemoryStock.empty())
54 {
55 // No free slot available, allocate a new one
56 fAllocated += fChunkSize;
57 return std::shared_ptr<char>(new char[fChunkSize]);
58 }
59
60 // Get the next free slot from the stack and return it
61 const std::lock_guard<std::mutex> lock(fMutexMem);
62
63 const auto mem = fMemoryStock.front();
64 fMemoryStock.pop_front();
65 return mem;
66 };
67
68 void push(const std::shared_ptr<char> &mem)
69 {
70 if (!mem)
71 return;
72
73 // Decrease the amont of memory in use accordingly
74 fInUse -= fChunkSize;
75
76 // If the maximum memory has changed, we might be over the limit.
77 // In this case: free a slot
78 if (fAllocated>fMaxMemory)
79 {
80 fAllocated -= fChunkSize;
81 return;
82 }
83
84 {
85 const std::lock_guard<std::mutex> lock(fMutexMem);
86 fMemoryStock.emplace_front(mem);
87 }
88
89 {
90 const std::lock_guard<std::mutex> lock(fMutexCond);
91 fCond.notify_one();
92 }
93 }
94};
95
96class MemoryChunk
97{
98 friend class MemoryManager;
99
100 std::shared_ptr<MemoryStock> fMemoryStock;
101 std::shared_ptr<char> fPointer;
102 char* fRealPointer;
103
104 MemoryChunk(const std::shared_ptr<MemoryStock> &mem, bool block) : fMemoryStock(mem)
105 {
106 fPointer = fMemoryStock->pop(block);
107 fRealPointer = fPointer.get();
108 }
109
110public:
111 ~MemoryChunk()
112 {
113 fMemoryStock->push(fPointer);
114 }
115
116public:
117 char* get() { return fPointer.get();}
118};
119
120class MemoryManager
121{
122 std::shared_ptr<MemoryStock> fMemoryStock;
123
124public:
125
126 MemoryManager(size_t chunk, size_t max) : fMemoryStock(std::make_shared<MemoryStock>(chunk, max))
127 {
128 }
129
130 std::shared_ptr<MemoryChunk> malloc(bool block=true)
131 {
132 MemoryChunk *chunk = new MemoryChunk(fMemoryStock, block);
133 //Etienne cannot get the aliasing to work (at least with g++ 4.4.6
134 return std::shared_ptr<MemoryChunk>(std::shared_ptr<MemoryChunk>(chunk));//, chunk->fRealPointer);
135 }
136
137 size_t getChunkSize() const { return fMemoryStock->fChunkSize; }
138 bool setChunkSize(const size_t size)
139 {
140#ifdef __EXCEPTIONS
141 if (getInUse())
142 throw std::runtime_error("Cannot change the chunk size while there is memory in use");
143 if (getMaxMemory()<size)
144 throw std::runtime_error("Chunk size("+to_string(size)+") larger thann allowed memory ("+to_string(getMaxMemory())+")");
145#else
146 if (getInUse() || getMaxMemory()<size)
147 return false;
148#endif
149
150 fMemoryStock->fChunkSize = size;
151 return true;
152 }
153
154 size_t getMaxMemory() const { return fMemoryStock->fMaxMemory; }
155 size_t getInUse() const { return fMemoryStock->fInUse; }
156 size_t getAllocated() const { return fMemoryStock->fAllocated; }
157 size_t getMaxInUse() const { return fMemoryStock->fMaxInUse; }
158};
159
160
Note: See TracBrowser for help on using the repository browser.