237 * which ensures 8-bytes alignment on 32-bit systems and 16-bytes on 64-bit systems (Product build). |
237 * which ensures 8-bytes alignment on 32-bit systems and 16-bytes on 64-bit systems (Product build). |
238 */ |
238 */ |
239 |
239 |
240 class MallocHeader VALUE_OBJ_CLASS_SPEC { |
240 class MallocHeader VALUE_OBJ_CLASS_SPEC { |
241 #ifdef _LP64 |
241 #ifdef _LP64 |
242 size_t _size : 62; |
242 size_t _size : 64; |
243 size_t _level : 2; |
|
244 size_t _flags : 8; |
243 size_t _flags : 8; |
245 size_t _pos_idx : 16; |
244 size_t _pos_idx : 16; |
246 size_t _bucket_idx: 40; |
245 size_t _bucket_idx: 40; |
247 #define MAX_MALLOCSITE_TABLE_SIZE ((size_t)1 << 40) |
246 #define MAX_MALLOCSITE_TABLE_SIZE ((size_t)1 << 40) |
248 #define MAX_BUCKET_LENGTH ((size_t)(1 << 16)) |
247 #define MAX_BUCKET_LENGTH ((size_t)(1 << 16)) |
249 #define MAX_MALLOC_SIZE (((size_t)1 << 62) - 1) |
|
250 #else |
248 #else |
251 size_t _size : 30; |
249 size_t _size : 32; |
252 size_t _level : 2; |
|
253 size_t _flags : 8; |
250 size_t _flags : 8; |
254 size_t _pos_idx : 8; |
251 size_t _pos_idx : 8; |
255 size_t _bucket_idx: 16; |
252 size_t _bucket_idx: 16; |
256 #define MAX_MALLOCSITE_TABLE_SIZE ((size_t)(1 << 16)) |
253 #define MAX_MALLOCSITE_TABLE_SIZE ((size_t)(1 << 16)) |
257 #define MAX_BUCKET_LENGTH ((size_t)(1 << 8)) |
254 #define MAX_BUCKET_LENGTH ((size_t)(1 << 8)) |
258 // Max malloc size = 1GB - 1 on 32 bit system, such has total 4GB memory |
|
259 #define MAX_MALLOC_SIZE ((size_t)(1 << 30) - 1) |
|
260 #endif // _LP64 |
255 #endif // _LP64 |
261 |
256 |
262 public: |
257 public: |
263 // Summary tracking header |
258 MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack, NMT_TrackingLevel level) { |
264 MallocHeader(size_t size, MEMFLAGS flags) { |
|
265 assert(sizeof(MallocHeader) == sizeof(void*) * 2, |
259 assert(sizeof(MallocHeader) == sizeof(void*) * 2, |
266 "Wrong header size"); |
260 "Wrong header size"); |
267 |
261 |
268 _level = NMT_summary; |
262 if (level == NMT_minimal) { |
|
263 return; |
|
264 } |
|
265 |
269 _flags = flags; |
266 _flags = flags; |
270 set_size(size); |
267 set_size(size); |
|
268 if (level == NMT_detail) { |
|
269 size_t bucket_idx; |
|
270 size_t pos_idx; |
|
271 if (record_malloc_site(stack, size, &bucket_idx, &pos_idx)) { |
|
272 assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index"); |
|
273 assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index"); |
|
274 _bucket_idx = bucket_idx; |
|
275 _pos_idx = pos_idx; |
|
276 } |
|
277 } |
|
278 |
271 MallocMemorySummary::record_malloc(size, flags); |
279 MallocMemorySummary::record_malloc(size, flags); |
272 MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader)); |
280 MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader)); |
273 } |
|
274 // Detail tracking header |
|
275 MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack) { |
|
276 assert(sizeof(MallocHeader) == sizeof(void*) * 2, |
|
277 "Wrong header size"); |
|
278 |
|
279 _level = NMT_detail; |
|
280 _flags = flags; |
|
281 set_size(size); |
|
282 size_t bucket_idx; |
|
283 size_t pos_idx; |
|
284 if (record_malloc_site(stack, size, &bucket_idx, &pos_idx)) { |
|
285 assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index"); |
|
286 assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index"); |
|
287 _bucket_idx = bucket_idx; |
|
288 _pos_idx = pos_idx; |
|
289 } |
|
290 MallocMemorySummary::record_malloc(size, flags); |
|
291 MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader)); |
|
292 } |
|
293 // Minimal tracking header |
|
294 MallocHeader() { |
|
295 assert(sizeof(MallocHeader) == sizeof(void*) * 2, |
|
296 "Wrong header size"); |
|
297 |
|
298 _level = (unsigned short)NMT_minimal; |
|
299 } |
|
300 |
|
301 inline NMT_TrackingLevel tracking_level() const { |
|
302 return (NMT_TrackingLevel)_level; |
|
303 } |
281 } |
304 |
282 |
305 inline size_t size() const { return _size; } |
283 inline size_t size() const { return _size; } |
306 inline MEMFLAGS flags() const { return (MEMFLAGS)_flags; } |
284 inline MEMFLAGS flags() const { return (MEMFLAGS)_flags; } |
307 bool get_stack(NativeCallStack& stack) const; |
285 bool get_stack(NativeCallStack& stack) const; |
309 // Cleanup tracking information before the memory is released. |
287 // Cleanup tracking information before the memory is released. |
310 void release() const; |
288 void release() const; |
311 |
289 |
312 private: |
290 private: |
313 inline void set_size(size_t size) { |
291 inline void set_size(size_t size) { |
314 assert(size <= MAX_MALLOC_SIZE, "Malloc size too large, should use virtual memory?"); |
|
315 _size = size; |
292 _size = size; |
316 } |
293 } |
317 bool record_malloc_site(const NativeCallStack& stack, size_t size, |
294 bool record_malloc_site(const NativeCallStack& stack, size_t size, |
318 size_t* bucket_idx, size_t* pos_idx) const; |
295 size_t* bucket_idx, size_t* pos_idx) const; |
319 }; |
296 }; |
345 const NativeCallStack& stack, NMT_TrackingLevel level); |
322 const NativeCallStack& stack, NMT_TrackingLevel level); |
346 |
323 |
347 // Record free on specified memory block |
324 // Record free on specified memory block |
348 static void* record_free(void* memblock); |
325 static void* record_free(void* memblock); |
349 |
326 |
350 // Get tracking level of specified memory block |
|
351 static inline NMT_TrackingLevel get_memory_tracking_level(void* memblock); |
|
352 |
|
353 |
|
354 // Offset memory address to header address |
327 // Offset memory address to header address |
355 static inline void* get_base(void* memblock); |
328 static inline void* get_base(void* memblock); |
356 static inline void* get_base(void* memblock, NMT_TrackingLevel level) { |
329 static inline void* get_base(void* memblock, NMT_TrackingLevel level) { |
357 if (memblock == NULL || level == NMT_off) return memblock; |
330 if (memblock == NULL || level == NMT_off) return memblock; |
358 return (char*)memblock - malloc_header_size(level); |
331 return (char*)memblock - malloc_header_size(level); |
359 } |
332 } |
360 |
333 |
361 // Get memory size |
334 // Get memory size |
362 static inline size_t get_size(void* memblock) { |
335 static inline size_t get_size(void* memblock) { |
363 MallocHeader* header = malloc_header(memblock); |
336 MallocHeader* header = malloc_header(memblock); |
364 assert(header->tracking_level() >= NMT_summary, |
|
365 "Wrong tracking level"); |
|
366 return header->size(); |
337 return header->size(); |
367 } |
338 } |
368 |
339 |
369 // Get memory type |
340 // Get memory type |
370 static inline MEMFLAGS get_flags(void* memblock) { |
341 static inline MEMFLAGS get_flags(void* memblock) { |
371 MallocHeader* header = malloc_header(memblock); |
342 MallocHeader* header = malloc_header(memblock); |
372 assert(header->tracking_level() >= NMT_summary, |
|
373 "Wrong tracking level"); |
|
374 return header->flags(); |
343 return header->flags(); |
375 } |
344 } |
376 |
345 |
377 // Get header size |
346 // Get header size |
378 static inline size_t get_header_size(void* memblock) { |
347 static inline size_t get_header_size(void* memblock) { |