Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/services/mallocTracker.hpp
32285 views
/*1* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_VM_SERVICES_MALLOC_TRACKER_HPP25#define SHARE_VM_SERVICES_MALLOC_TRACKER_HPP2627#if INCLUDE_NMT2829#include "memory/allocation.hpp"30#include "runtime/atomic.hpp"31#include "services/nmtCommon.hpp"32#include "utilities/nativeCallStack.hpp"3334/*35* This counter class counts memory allocation and deallocation,36* records total memory allocation size and number of allocations.37* The counters are updated atomically.38*/39class MemoryCounter VALUE_OBJ_CLASS_SPEC {40private:41size_t _count;42size_t _size;4344DEBUG_ONLY(size_t _peak_count;)45DEBUG_ONLY(size_t _peak_size; )4647public:48MemoryCounter() : _count(0), _size(0) {49DEBUG_ONLY(_peak_count = 0;)50DEBUG_ONLY(_peak_size = 0;)51}5253inline void allocate(size_t sz) {54Atomic::add(1, (volatile MemoryCounterType*)&_count);55if (sz > 0) {56Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);57DEBUG_ONLY(_peak_size = MAX2(_peak_size, _size));58}59DEBUG_ONLY(_peak_count = MAX2(_peak_count, _count);)60}6162inline void deallocate(size_t sz) {63assert(_count > 0, "Negative counter");64assert(_size >= sz, "Negative size");65Atomic::add(-1, (volatile MemoryCounterType*)&_count);66if (sz > 0) {67Atomic::add(-(MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);68}69}7071inline void resize(ssize_t sz) {72if (sz != 0) {73assert(sz >= 0 || _size >= size_t(-sz), "Must be");74Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);75DEBUG_ONLY(_peak_size = MAX2(_size, _peak_size);)76}77}7879inline size_t count() const { return _count; }80inline size_t size() const { return _size; }81DEBUG_ONLY(inline size_t peak_count() const { return _peak_count; })82DEBUG_ONLY(inline size_t peak_size() const { return _peak_size; })8384};8586/*87* Malloc memory used by a particular subsystem.88* It includes the memory acquired through os::malloc()89* call and arena's backing memory.90*/91class MallocMemory VALUE_OBJ_CLASS_SPEC {92private:93MemoryCounter _malloc;94MemoryCounter _arena;9596public:97MallocMemory() { }9899inline void record_malloc(size_t sz) {100_malloc.allocate(sz);101}102103inline void record_free(size_t sz) {104_malloc.deallocate(sz);105}106107inline void record_new_arena() {108_arena.allocate(0);109}110111inline void record_arena_free() {112_arena.deallocate(0);113}114115inline void record_arena_size_change(ssize_t sz) {116_arena.resize(sz);117}118119inline size_t malloc_size() const { return _malloc.size(); }120inline size_t malloc_count() const { return _malloc.count();}121inline size_t arena_size() const { return _arena.size(); }122inline size_t arena_count() const { return _arena.count(); }123124DEBUG_ONLY(inline const MemoryCounter& malloc_counter() const { return _malloc; })125DEBUG_ONLY(inline const MemoryCounter& arena_counter() const { return _arena; })126};127128class MallocMemorySummary;129130// A snapshot of malloc'd memory, includes malloc memory131// usage by types and memory used by tracking itself.132class MallocMemorySnapshot : public ResourceObj {133friend class MallocMemorySummary;134135private:136MallocMemory _malloc[mt_number_of_types];137MemoryCounter _tracking_header;138139140public:141inline MallocMemory* by_type(MEMFLAGS flags) {142int index = NMTUtil::flag_to_index(flags);143return &_malloc[index];144}145146inline MallocMemory* by_index(int index) {147assert(index >= 0, "Index out of bound");148assert(index < mt_number_of_types, "Index out of bound");149return &_malloc[index];150}151152inline MemoryCounter* malloc_overhead() {153return &_tracking_header;154}155156// Total malloc'd memory amount157size_t total() const;158// Total malloc'd memory used by arenas159size_t total_arena() const;160161inline size_t thread_count() const {162MallocMemorySnapshot* s = const_cast<MallocMemorySnapshot*>(this);163return s->by_type(mtThreadStack)->malloc_count();164}165166void copy_to(MallocMemorySnapshot* s) {167s->_tracking_header = _tracking_header;168for (int index = 0; index < mt_number_of_types; index ++) {169s->_malloc[index] = _malloc[index];170}171}172173// Make adjustment by subtracting chunks used by arenas174// from total chunks to get total free chunk size175void make_adjustment();176};177178/*179* This class is for collecting malloc statistics at summary level180*/181class MallocMemorySummary : AllStatic {182private:183// Reserve memory for placement of MallocMemorySnapshot object184static size_t _snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)];185186public:187static void initialize();188189static inline void record_malloc(size_t size, MEMFLAGS flag) {190as_snapshot()->by_type(flag)->record_malloc(size);191}192193static inline void record_free(size_t size, MEMFLAGS flag) {194as_snapshot()->by_type(flag)->record_free(size);195}196197static inline void record_new_arena(MEMFLAGS flag) {198as_snapshot()->by_type(flag)->record_new_arena();199}200201static inline void record_arena_free(MEMFLAGS flag) {202as_snapshot()->by_type(flag)->record_arena_free();203}204205static inline void record_arena_size_change(ssize_t size, MEMFLAGS flag) {206as_snapshot()->by_type(flag)->record_arena_size_change(size);207}208209static void snapshot(MallocMemorySnapshot* s) {210as_snapshot()->copy_to(s);211s->make_adjustment();212}213214// Record memory used by malloc tracking header215static inline void record_new_malloc_header(size_t sz) {216as_snapshot()->malloc_overhead()->allocate(sz);217}218219static inline void record_free_malloc_header(size_t sz) {220as_snapshot()->malloc_overhead()->deallocate(sz);221}222223// The memory used by malloc tracking headers224static inline size_t tracking_overhead() {225return as_snapshot()->malloc_overhead()->size();226}227228static MallocMemorySnapshot* as_snapshot() {229return (MallocMemorySnapshot*)_snapshot;230}231};232233234/*235* Malloc tracking header.236* To satisfy malloc alignment requirement, NMT uses 2 machine words for tracking purpose,237* which ensures 8-bytes alignment on 32-bit systems and 16-bytes on 64-bit systems (Product build).238*/239240class MallocHeader VALUE_OBJ_CLASS_SPEC {241#ifdef _LP64242size_t _size : 64;243size_t _flags : 8;244size_t _pos_idx : 16;245size_t _bucket_idx: 40;246#define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(40)247#define MAX_BUCKET_LENGTH right_n_bits(16)248#else249size_t _size : 32;250size_t _flags : 8;251size_t _pos_idx : 8;252size_t _bucket_idx: 16;253#define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(16)254#define MAX_BUCKET_LENGTH right_n_bits(8)255#endif // _LP64256257public:258MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack, NMT_TrackingLevel level) {259assert(sizeof(MallocHeader) == sizeof(void*) * 2,260"Wrong header size");261262if (level == NMT_minimal) {263return;264}265266_flags = flags;267set_size(size);268if (level == NMT_detail) {269size_t bucket_idx;270size_t pos_idx;271if (record_malloc_site(stack, size, &bucket_idx, &pos_idx, flags)) {272assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index");273assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index");274_bucket_idx = bucket_idx;275_pos_idx = pos_idx;276}277}278279MallocMemorySummary::record_malloc(size, flags);280MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader));281}282283inline size_t size() const { return _size; }284inline MEMFLAGS flags() const { return (MEMFLAGS)_flags; }285bool get_stack(NativeCallStack& stack) const;286287// Cleanup tracking information before the memory is released.288void release() const;289290private:291inline void set_size(size_t size) {292_size = size;293}294bool record_malloc_site(const NativeCallStack& stack, size_t size,295size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) const;296};297298299// Main class called from MemTracker to track malloc activities300class MallocTracker : AllStatic {301public:302// Initialize malloc tracker for specific tracking level303static bool initialize(NMT_TrackingLevel level);304305static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to);306307// malloc tracking header size for specific tracking level308static inline size_t malloc_header_size(NMT_TrackingLevel level) {309return (level == NMT_off) ? 0 : sizeof(MallocHeader);310}311312// Parameter name convention:313// memblock : the beginning address for user data314// malloc_base: the beginning address that includes malloc tracking header315//316// The relationship:317// memblock = (char*)malloc_base + sizeof(nmt header)318//319320// Record malloc on specified memory block321static void* record_malloc(void* malloc_base, size_t size, MEMFLAGS flags,322const NativeCallStack& stack, NMT_TrackingLevel level);323324// Record free on specified memory block325static void* record_free(void* memblock);326327// Offset memory address to header address328static inline void* get_base(void* memblock);329static inline void* get_base(void* memblock, NMT_TrackingLevel level) {330if (memblock == NULL || level == NMT_off) return memblock;331return (char*)memblock - malloc_header_size(level);332}333334// Get memory size335static inline size_t get_size(void* memblock) {336MallocHeader* header = malloc_header(memblock);337return header->size();338}339340// Get memory type341static inline MEMFLAGS get_flags(void* memblock) {342MallocHeader* header = malloc_header(memblock);343return header->flags();344}345346// Get header size347static inline size_t get_header_size(void* memblock) {348return (memblock == NULL) ? 0 : sizeof(MallocHeader);349}350351static inline void record_new_arena(MEMFLAGS flags) {352MallocMemorySummary::record_new_arena(flags);353}354355static inline void record_arena_free(MEMFLAGS flags) {356MallocMemorySummary::record_arena_free(flags);357}358359static inline void record_arena_size_change(ssize_t size, MEMFLAGS flags) {360MallocMemorySummary::record_arena_size_change(size, flags);361}362private:363static inline MallocHeader* malloc_header(void *memblock) {364assert(memblock != NULL, "NULL pointer");365MallocHeader* header = (MallocHeader*)((char*)memblock - sizeof(MallocHeader));366return header;367}368};369370#endif // INCLUDE_NMT371372373#endif //SHARE_VM_SERVICES_MALLOC_TRACKER_HPP374375376