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

Last change on this file since 17261 was 17254, checked in by tbretz, 11 years ago
Use a shared_ptr with aliasing of char* instead of a MemoryChunk
File size: 4.1 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
103 MemoryChunk(const std::shared_ptr<MemoryStock> &mem, bool block)
104 : fMemoryStock(mem)
105 {
106 fPointer = fMemoryStock->pop(block);
107 }
108
109public:
110 ~MemoryChunk()
111 {
112 fMemoryStock->push(fPointer);
113 }
114};
115
116class MemoryManager
117{
118 std::shared_ptr<MemoryStock> fMemoryStock;
119
120public:
121 MemoryManager(size_t chunk, size_t max) : fMemoryStock(std::make_shared<MemoryStock>(chunk, max))
122 {
123 }
124
125 std::shared_ptr<char> malloc(bool block=true)
126 {
127 const std::shared_ptr<MemoryChunk> chunk(new MemoryChunk(fMemoryStock, block));
128 return std::shared_ptr<char>(chunk, chunk->fPointer.get());
129 }
130
131 size_t getChunkSize() const { return fMemoryStock->fChunkSize; }
132 bool setChunkSize(const size_t size)
133 {
134#ifdef __EXCEPTIONS
135 if (getInUse())
136 throw std::runtime_error("Cannot change the chunk size while there is memory in use");
137 if (getMaxMemory()<size)
138 throw std::runtime_error("Chunk size ("+std::to_string(size)+") larger than allowed memory ("+std::to_string(getMaxMemory())+")");
139#else
140 if (getInUse() || getMaxMemory()<size)
141 return false;
142#endif
143
144 fMemoryStock->fChunkSize = size;
145 return true;
146 }
147
148 size_t getMaxMemory() const { return fMemoryStock->fMaxMemory; }
149 size_t getInUse() const { return fMemoryStock->fInUse; }
150 size_t getAllocated() const { return fMemoryStock->fAllocated; }
151 size_t getMaxInUse() const { return fMemoryStock->fMaxInUse; }
152};
153
154
Note: See TracBrowser for help on using the repository browser.