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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
// Copyright 2011 Google Inc. All Rights Reserved.
#include "heap.h"
#include <vector>
#include "mark_sweep.h"
#include "object.h"
#include "space.h"
#include "scoped_ptr.h"
#include "stl_util.h"
namespace art {
std::vector<Space*> Heap::spaces_;
size_t Heap::startup_size_ = 0;
size_t Heap::maximum_size_ = 0;
size_t Heap::num_bytes_allocated_ = 0;
size_t Heap::num_objects_allocated_ = 0;
bool Heap::is_gc_running_ = false;
HeapBitmap* Heap::mark_bitmap_ = NULL;
HeapBitmap* Heap::live_bitmap_ = NULL;
bool Heap::Init(size_t startup_size, size_t maximum_size) {
Space* space = Space::Create(startup_size, maximum_size);
if (space == NULL) {
return false;
}
byte* base = space->GetBase();
size_t num_bytes = space->Size();
// Allocate the initial live bitmap.
scoped_ptr<HeapBitmap> live_bitmap(HeapBitmap::Create(base, num_bytes));
if (live_bitmap == NULL) {
return false;
}
// Allocate the initial mark bitmap.
scoped_ptr<HeapBitmap> mark_bitmap(HeapBitmap::Create(base, num_bytes));
if (mark_bitmap == NULL) {
return false;
}
spaces_.push_back(space);
startup_size_ = startup_size;
maximum_size_ = maximum_size;
live_bitmap_ = live_bitmap.release();
mark_bitmap_ = mark_bitmap.release();
// TODO: allocate the card table
return true;
}
void Heap::Destroy() {
STLDeleteElements(&spaces_);
delete mark_bitmap_;
delete live_bitmap_;
}
Object* Heap::AllocObject(Class* klass, size_t num_bytes) {
DCHECK((klass == NULL && num_bytes == sizeof(Class))
|| klass->descriptor_ == NULL
|| (klass->object_size_ == (klass->IsArray() ? 0 : num_bytes)));
Object* obj = Allocate(num_bytes);
if (obj != NULL) {
obj->klass_ = klass;
}
return obj;
}
void Heap::RecordAllocation(Space* space, const Object* obj) {
size_t size = space->AllocationSize(obj);
DCHECK_NE(size, 0u);
num_bytes_allocated_ += size;
num_objects_allocated_ += 1;
live_bitmap_->Set(obj);
}
void Heap::RecordFree(Space* space, const Object* obj) {
size_t size = space->AllocationSize(obj);
DCHECK_NE(size, 0u);
if (size < num_bytes_allocated_) {
num_bytes_allocated_ -= size;
} else {
num_bytes_allocated_ = 0;
}
live_bitmap_->Clear(obj);
if (num_objects_allocated_ > 0) {
num_objects_allocated_ -= 1;
}
}
Object* Heap::Allocate(size_t size) {
CHECK_EQ(spaces_.size(), 1u);
Space* space = spaces_[0];
Object* obj = Allocate(space, size);
if (obj != NULL) {
RecordAllocation(space, obj);
}
return obj;
}
Object* Heap::Allocate(Space* space, size_t size) {
// Fail impossible allocations. TODO: collect soft references.
if (size > maximum_size_) {
return NULL;
}
Object* ptr = space->AllocWithoutGrowth(size);
if (ptr != NULL) {
return ptr;
}
// The allocation failed. If the GC is running, block until it
// completes and retry.
if (is_gc_running_) {
// The GC is concurrently tracing the heap. Release the heap
// lock, wait for the GC to complete, and retrying allocating.
WaitForConcurrentGcToComplete();
ptr = space->AllocWithoutGrowth(size);
if (ptr != NULL) {
return ptr;
}
}
// Another failure. Our thread was starved or there may be too many
// live objects. Try a foreground GC. This will have no effect if
// the concurrent GC is already running.
CollectGarbageInternal();
ptr = space->AllocWithoutGrowth(size);
if (ptr != NULL) {
return ptr;
}
// Even that didn't work; this is an exceptional state.
// Try harder, growing the heap if necessary.
ptr = space->AllocWithGrowth(size);
if (ptr != NULL) {
//size_t new_footprint = dvmHeapSourceGetIdealFootprint();
size_t new_footprint = space->MaxAllowedFootprint();
// TODO: may want to grow a little bit more so that the amount of
// free space is equal to the old free space + the
// utilization slop for the new allocation.
LOG(INFO) << "Grow heap (frag case) to " << new_footprint / MB
<< "for " << size << "-byte allocation";
return ptr;
}
// Most allocations should have succeeded by now, so the heap is
// really full, really fragmented, or the requested size is really
// big. Do another GC, collecting SoftReferences this time. The VM
// spec requires that all SoftReferences have been collected and
// cleared before throwing an OOME.
// TODO: wait for the finalizers from the previous GC to finish
LOG(INFO) << "Forcing collection of SoftReferences for "
<< size << "-byte allocation";
CollectGarbageInternal();
ptr = space->AllocWithGrowth(size);
if (ptr != NULL) {
return ptr;
}
LOG(ERROR) << "Out of memory on a " << size << " byte allocation";
// TODO: tell the HeapSource to dump its state
// TODO: dump stack traces for all threads
return NULL;
}
void Heap::CollectGarbage() {
CollectGarbageInternal();
}
void Heap::CollectGarbageInternal() {
// TODO: check that heap lock is held
// TODO: Suspend all threads
{
MarkSweep mark_sweep;
mark_sweep.Init();
mark_sweep.MarkRoots();
// Push marked roots onto the mark stack
// TODO: if concurrent
// unlock heap
// resume threads
mark_sweep.RecursiveMark();
// TODO: if concurrent
// lock heap
// suspend threads
// re-mark root set
// scan dirty objects
mark_sweep.ProcessReferences(false);
// TODO: swap bitmaps
mark_sweep.Sweep();
}
GrowForUtilization();
// TODO: Resume all threads
}
void Heap::WaitForConcurrentGcToComplete() {
}
// Given the current contents of the active heap, increase the allowed
// heap footprint to match the target utilization ratio. This should
// only be called immediately after a full garbage collection.
void Heap::GrowForUtilization() {
UNIMPLEMENTED(ERROR);
}
} // namespace art
|