-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGarbageCollector.h
159 lines (133 loc) · 3.7 KB
/
GarbageCollector.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// GarbageCollector.h
#pragma once
#include <ConfigurableFirmata.h>
#include "FirmataIlExecutor.h"
#include "ObjectVector.h"
class FirmataIlExecutor;
/* This must be smaller than 32k, because we use only 2 bytes for the next pointer and need one bit for free/in use */
#ifdef ARDUINO_DUE
const uint32_t DEFAULT_GC_BLOCK_SIZE = 8192;
#else
const uint32_t DEFAULT_GC_BLOCK_SIZE = 32 * 1024;
#endif
const byte BLOCK_MARKER = 0xf7;
enum class BlockFlags : byte
{
Used = 0,
Free = 1,
};
inline BlockFlags operator | (BlockFlags lhs, BlockFlags rhs)
{
return (BlockFlags)((byte)lhs | (byte)rhs);
}
inline BlockFlags operator & (BlockFlags lhs, BlockFlags rhs)
{
return (BlockFlags)((byte)lhs & (byte)rhs);
}
// This represents the header for one memory block returned by Allocate()
struct BlockHd
{
uint16_t BlockSize;
byte Marker; // should be 0xf7
BlockFlags flags;
bool IsFree()
{
return ((flags & BlockFlags::Free) == BlockFlags::Free);
}
static BlockHd* Cast(void* address)
{
return (BlockHd*)address;
}
static void SetBlockAtAddress(void* address, uint16_t size, BlockFlags flags)
{
BlockHd* block_hd = Cast(address);
block_hd->BlockSize = size;
block_hd->Marker = BLOCK_MARKER;
block_hd->flags = flags;
}
static short GetBlockSizeAtAddress(void* address)
{
BlockHd* block_hd = Cast(address);
return block_hd->BlockSize;
}
};
// This is the block allignment size and must also be equal to the size of the above struct
const uint32_t ALLOCATE_ALLIGNMENT = (sizeof(BlockHd));
/// <summary>
/// A continuous block of GC-Controlled memory. Within each block, a header of type BlockHd is used to separate the elements
/// </summary>
class GcBlock
{
public:
GcBlock()
{
BlockStart = nullptr;
BlockSize = 0;
FreeBytesInBlock = 0;
Tail = nullptr;
Preallocated = false;
}
BlockHd* BlockStart;
uint16_t BlockSize;
uint16_t FreeBytesInBlock;
BlockHd* Tail;
bool Preallocated;
};
class GarbageCollector
{
public:
GarbageCollector()
{
_totalAllocSize = 0;
_totalAllocations = 0;
_currentMemoryUsage = 0;
_maxMemoryUsage = 0;
_numAllocsSinceLastGc = 0;
_bytesAllocatedSinceLastGc = 0;
_totalGcMemorySize = 0;
_gcPressureHigh = false;
}
byte* TryAllocateFromBlock(GcBlock& block, uint32_t size);
byte* Allocate(uint32_t size, FirmataIlExecutor* referenceContainer);
byte* Allocate(uint32_t size, bool preallocateOnly, FirmataIlExecutor* referenceContainer);
void ValidateBlock(GcBlock& block);
void ValidateBlocks();
byte* AllocateBlock(GcBlock& block, uint32_t realSizeToReserve, BlockHd* hd);
void MarkDependentHandles(FirmataIlExecutor* referenceContainer);
int Collect(int generation, FirmataIlExecutor* referenceContainer);
void Clear(bool printStatistics, bool all);
void PrintStatistics();
bool GcRecommended()
{
return _gcPressureHigh;
}
void Init(FirmataIlExecutor* referenceContainer, size_t preallocateSize);
int64_t TotalAllocatedBytes() const
{
return _totalAllocSize;
}
int64_t TotalMemory()
{
return _currentMemoryUsage;
}
int64_t AllocatedMemory();
private:
void MarkAllFree();
void MarkAllFree(GcBlock& block);
int ComputeFreeBlockSizes();
void MarkStatics(FirmataIlExecutor* referenceContainer);
void MarkStacks(FirmataIlExecutor* referenceContainer);
bool IsValidMemoryPointer(void* ptr);
void MarkRawMemoryBlock(void* object, size_t objectSize, FirmataIlExecutor* referenceContainer);
void MarkVariable(Variable& variable, FirmataIlExecutor* referenceContainer);
int _totalAllocSize;
int _totalAllocations;
int _currentMemoryUsage;
int _maxMemoryUsage;
int _numAllocsSinceLastGc;
int _bytesAllocatedSinceLastGc;
size_t _totalGcMemorySize;
size_t _largestFreeBlock;
bool _gcPressureHigh;
stdSimple::vector<GcBlock, size_t, 10> _gcBlocks;
};