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

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