Mercurial > hg > graal-jvmci-8
comparison src/share/vm/services/memSnapshot.hpp @ 6741:33143ee07800
7181995: NMT ON: NMT assertion failure assert(cur_vm->is_uncommit_record() || cur_vm->is_deallocation_record
Summary: Fixed virtual memory records merge and promotion logic, should be based on sequence number vs. base address order
Reviewed-by: coleenp, acorn
author | zgu |
---|---|
date | Tue, 11 Sep 2012 20:53:17 -0400 |
parents | 4acebbe310e1 |
children | 716c64bda5ba |
comparison
equal
deleted
inserted
replaced
6730:5d2156bcb78b | 6741:33143ee07800 |
---|---|
109 public: | 109 public: |
110 VMMemPointerIterator(MemPointerArray* arr): | 110 VMMemPointerIterator(MemPointerArray* arr): |
111 MemPointerIterator(arr) { | 111 MemPointerIterator(arr) { |
112 } | 112 } |
113 | 113 |
114 // locate an exiting record that contains specified address, or | 114 // locate an existing record that contains specified address, or |
115 // the record, where the record with specified address, should | 115 // the record, where the record with specified address, should |
116 // be inserted | 116 // be inserted. |
117 // virtual memory record array is sorted in address order, so | |
118 // binary search is performed | |
117 virtual MemPointer* locate(address addr) { | 119 virtual MemPointer* locate(address addr) { |
118 VMMemRegion* cur = (VMMemRegion*)current(); | 120 int index_low = 0; |
119 VMMemRegion* next_p; | 121 int index_high = _array->length(); |
120 | 122 int index_mid = (index_high + index_low) / 2; |
121 while (cur != NULL) { | 123 int r = 1; |
122 if (cur->base() > addr) { | 124 while (index_low < index_high && (r = compare(index_mid, addr)) != 0) { |
123 return cur; | 125 if (r > 0) { |
126 index_high = index_mid; | |
124 } else { | 127 } else { |
125 // find nearest existing range that has base address <= addr | 128 index_low = index_mid; |
126 next_p = (VMMemRegion*)peek_next(); | |
127 if (next_p != NULL && next_p->base() <= addr) { | |
128 cur = (VMMemRegion*)next(); | |
129 continue; | |
130 } | |
131 } | 129 } |
132 | 130 index_mid = (index_high + index_low) / 2; |
133 if (cur->is_reserve_record() && | 131 } |
134 cur->base() <= addr && | 132 if (r == 0) { |
135 (cur->base() + cur->size() > addr)) { | 133 // update current location |
136 return cur; | 134 _pos = index_mid; |
137 } else if (cur->is_commit_record() && | 135 return _array->at(index_mid); |
138 cur->base() <= addr && | 136 } else { |
139 (cur->base() + cur->committed_size() > addr)) { | 137 return NULL; |
140 return cur; | 138 } |
141 } | |
142 cur = (VMMemRegion*)next(); | |
143 } | |
144 return NULL; | |
145 } | 139 } |
146 | 140 |
147 #ifdef ASSERT | 141 #ifdef ASSERT |
148 virtual bool is_dup_pointer(const MemPointer* ptr1, | 142 virtual bool is_dup_pointer(const MemPointer* ptr1, |
149 const MemPointer* ptr2) const { | 143 const MemPointer* ptr2) const { |
158 // we do see multiple commit/uncommit on the same memory, it is ok | 152 // we do see multiple commit/uncommit on the same memory, it is ok |
159 return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc || | 153 return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc || |
160 (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release; | 154 (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release; |
161 } | 155 } |
162 #endif | 156 #endif |
163 }; | 157 // compare if an address falls into a memory region, |
164 | 158 // return 0, if the address falls into a memory region at specified index |
165 class StagingWalker : public MemPointerArrayIterator { | 159 // return 1, if memory region pointed by specified index is higher than the address |
160 // return -1, if memory region pointed by specified index is lower than the address | |
161 int compare(int index, address addr) const { | |
162 VMMemRegion* r = (VMMemRegion*)_array->at(index); | |
163 assert(r->is_reserve_record(), "Sanity check"); | |
164 if (r->addr() > addr) { | |
165 return 1; | |
166 } else if (r->addr() + r->reserved_size() <= addr) { | |
167 return -1; | |
168 } else { | |
169 return 0; | |
170 } | |
171 } | |
172 }; | |
173 | |
174 class MallocRecordIterator : public MemPointerArrayIterator { | |
166 private: | 175 private: |
167 MemPointerArrayIteratorImpl _itr; | 176 MemPointerArrayIteratorImpl _itr; |
168 bool _is_vm_record; | 177 |
169 bool _end_of_array; | 178 public: |
170 VMMemRegionEx _vm_record; | 179 MallocRecordIterator(MemPointerArray* arr) : _itr(arr) { |
171 MemPointerRecordEx _malloc_record; | 180 } |
172 | 181 |
173 public: | |
174 StagingWalker(MemPointerArray* arr): _itr(arr) { | |
175 _end_of_array = false; | |
176 next(); | |
177 } | |
178 | |
179 // return the pointer at current position | |
180 MemPointer* current() const { | 182 MemPointer* current() const { |
181 if (_end_of_array) { | 183 MemPointerRecord* cur = (MemPointerRecord*)_itr.current(); |
184 assert(cur == NULL || !cur->is_vm_pointer(), "seek error"); | |
185 MemPointerRecord* next = (MemPointerRecord*)_itr.peek_next(); | |
186 if (next == NULL || next->addr() != cur->addr()) { | |
187 return cur; | |
188 } else { | |
189 assert(!cur->is_vm_pointer(), "Sanity check"); | |
190 assert(cur->is_allocation_record() && next->is_deallocation_record(), | |
191 "sorting order"); | |
192 assert(cur->seq() != next->seq(), "Sanity check"); | |
193 return cur->seq() > next->seq() ? cur : next; | |
194 } | |
195 } | |
196 | |
197 MemPointer* next() { | |
198 MemPointerRecord* cur = (MemPointerRecord*)_itr.current(); | |
199 assert(cur == NULL || !cur->is_vm_pointer(), "Sanity check"); | |
200 MemPointerRecord* next = (MemPointerRecord*)_itr.next(); | |
201 if (next == NULL) { | |
182 return NULL; | 202 return NULL; |
183 } | 203 } |
184 if (is_vm_record()) { | 204 if (cur->addr() == next->addr()) { |
185 return (MemPointer*)&_vm_record; | 205 next = (MemPointerRecord*)_itr.next(); |
186 } else { | 206 } |
187 return (MemPointer*)&_malloc_record; | 207 return current(); |
188 } | 208 } |
189 } | 209 |
190 | 210 MemPointer* peek_next() const { ShouldNotReachHere(); return NULL; } |
191 // return the next pointer and advance current position | 211 MemPointer* peek_prev() const { ShouldNotReachHere(); return NULL; } |
192 MemPointer* next(); | 212 void remove() { ShouldNotReachHere(); } |
193 | 213 bool insert(MemPointer* ptr) { ShouldNotReachHere(); return false; } |
194 // type of 'current' record | 214 bool insert_after(MemPointer* ptr) { ShouldNotReachHere(); return false; } |
195 bool is_vm_record() const { | 215 }; |
196 return _is_vm_record; | 216 |
197 } | 217 class StagingArea : public _ValueObj { |
198 | |
199 // return the next poinger without advancing current position | |
200 MemPointer* peek_next() const { | |
201 assert(false, "not supported"); | |
202 return NULL; | |
203 } | |
204 | |
205 MemPointer* peek_prev() const { | |
206 assert(false, "not supported"); | |
207 return NULL; | |
208 } | |
209 // remove the pointer at current position | |
210 void remove() { | |
211 assert(false, "not supported"); | |
212 } | |
213 | |
214 // insert the pointer at current position | |
215 bool insert(MemPointer* ptr) { | |
216 assert(false, "not supported"); | |
217 return false; | |
218 } | |
219 | |
220 bool insert_after(MemPointer* ptr) { | |
221 assert(false, "not supported"); | |
222 return false; | |
223 } | |
224 | |
225 private: | 218 private: |
226 // consolidate all records referring to this vm region | 219 MemPointerArray* _malloc_data; |
227 bool consolidate_vm_records(VMMemRegionEx* vm_rec); | 220 MemPointerArray* _vm_data; |
221 | |
222 public: | |
223 StagingArea() : _malloc_data(NULL), _vm_data(NULL) { | |
224 init(); | |
225 } | |
226 | |
227 ~StagingArea() { | |
228 if (_malloc_data != NULL) delete _malloc_data; | |
229 if (_vm_data != NULL) delete _vm_data; | |
230 } | |
231 | |
232 MallocRecordIterator malloc_record_walker() { | |
233 return MallocRecordIterator(malloc_data()); | |
234 } | |
235 | |
236 MemPointerArrayIteratorImpl virtual_memory_record_walker(); | |
237 bool init(); | |
238 void clear() { | |
239 assert(_malloc_data != NULL && _vm_data != NULL, "Just check"); | |
240 _malloc_data->shrink(); | |
241 _malloc_data->clear(); | |
242 _vm_data->clear(); | |
243 } | |
244 | |
245 inline MemPointerArray* malloc_data() { return _malloc_data; } | |
246 inline MemPointerArray* vm_data() { return _vm_data; } | |
228 }; | 247 }; |
229 | 248 |
230 class MemBaseline; | 249 class MemBaseline; |
231 | |
232 class MemSnapshot : public CHeapObj<mtNMT> { | 250 class MemSnapshot : public CHeapObj<mtNMT> { |
233 private: | 251 private: |
234 // the following two arrays contain records of all known lived memory blocks | 252 // the following two arrays contain records of all known lived memory blocks |
235 // live malloc-ed memory pointers | 253 // live malloc-ed memory pointers |
236 MemPointerArray* _alloc_ptrs; | 254 MemPointerArray* _alloc_ptrs; |
237 // live virtual memory pointers | 255 // live virtual memory pointers |
238 MemPointerArray* _vm_ptrs; | 256 MemPointerArray* _vm_ptrs; |
239 | 257 |
240 // stagging a generation's data, before | 258 StagingArea _staging_area; |
241 // it can be prompted to snapshot | |
242 MemPointerArray* _staging_area; | |
243 | 259 |
244 // the lock to protect this snapshot | 260 // the lock to protect this snapshot |
245 Monitor* _lock; | 261 Monitor* _lock; |
246 | 262 |
247 NOT_PRODUCT(size_t _untracked_count;) | 263 NOT_PRODUCT(size_t _untracked_count;) |
250 public: | 266 public: |
251 MemSnapshot(); | 267 MemSnapshot(); |
252 virtual ~MemSnapshot(); | 268 virtual ~MemSnapshot(); |
253 | 269 |
254 // if we are running out of native memory | 270 // if we are running out of native memory |
255 bool out_of_memory() const { | 271 bool out_of_memory() { |
256 return (_alloc_ptrs == NULL || _staging_area == NULL || | 272 return (_alloc_ptrs == NULL || |
273 _staging_area.malloc_data() == NULL || | |
274 _staging_area.vm_data() == NULL || | |
257 _vm_ptrs == NULL || _lock == NULL || | 275 _vm_ptrs == NULL || _lock == NULL || |
258 _alloc_ptrs->out_of_memory() || | 276 _alloc_ptrs->out_of_memory() || |
259 _staging_area->out_of_memory() || | |
260 _vm_ptrs->out_of_memory()); | 277 _vm_ptrs->out_of_memory()); |
261 } | 278 } |
262 | 279 |
263 // merge a per-thread memory recorder into staging area | 280 // merge a per-thread memory recorder into staging area |
264 bool merge(MemRecorder* rec); | 281 bool merge(MemRecorder* rec); |
265 // promote staged data to snapshot | 282 // promote staged data to snapshot |
266 void promote(); | 283 bool promote(); |
267 | 284 |
268 | 285 |
269 void wait(long timeout) { | 286 void wait(long timeout) { |
270 assert(_lock != NULL, "Just check"); | 287 assert(_lock != NULL, "Just check"); |
271 MonitorLockerEx locker(_lock); | 288 MonitorLockerEx locker(_lock); |
278 NOT_PRODUCT(bool has_allocation_record(address addr);) | 295 NOT_PRODUCT(bool has_allocation_record(address addr);) |
279 | 296 |
280 private: | 297 private: |
281 // copy pointer data from src to dest | 298 // copy pointer data from src to dest |
282 void copy_pointer(MemPointerRecord* dest, const MemPointerRecord* src); | 299 void copy_pointer(MemPointerRecord* dest, const MemPointerRecord* src); |
300 | |
301 bool promote_malloc_records(MemPointerArrayIterator* itr); | |
302 bool promote_virtual_memory_records(MemPointerArrayIterator* itr); | |
283 }; | 303 }; |
284 | 304 |
285 | 305 |
286 #endif // SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP | 306 #endif // SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP |