mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 03:24:38 +02:00
6995781: Native Memory Tracking (Phase 1)
7151532: DCmd for hotspot native memory tracking Implementation of native memory tracking phase 1, which tracks VM native memory usage, and related DCmd Reviewed-by: acorn, coleenp, fparain
This commit is contained in:
parent
8e42425c92
commit
a39b17624a
315 changed files with 7245 additions and 1477 deletions
267
hotspot/src/share/vm/services/memRecorder.hpp
Normal file
267
hotspot/src/share/vm/services/memRecorder.hpp
Normal file
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_SERVICES_MEM_RECORDER_HPP
|
||||
#define SHARE_VM_SERVICES_MEM_RECORDER_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "services/memPtrArray.hpp"
|
||||
|
||||
class MemSnapshot;
|
||||
class MemTracker;
|
||||
class MemTrackWorker;
|
||||
|
||||
// Fixed size memory pointer array implementation
|
||||
template <class E, int SIZE> class FixedSizeMemPointerArray :
|
||||
public MemPointerArray {
|
||||
// This implementation is for memory recorder only
|
||||
friend class MemRecorder;
|
||||
|
||||
private:
|
||||
E _data[SIZE];
|
||||
int _size;
|
||||
|
||||
protected:
|
||||
FixedSizeMemPointerArray(bool init_elements = false):
|
||||
_size(0){
|
||||
if (init_elements) {
|
||||
for (int index = 0; index < SIZE; index ++) {
|
||||
::new ((void*)&_data[index]) E();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* operator new(size_t size, const std::nothrow_t& nothrow_constant) {
|
||||
// the instance is part of memRecorder, needs to be tagged with 'otNMTRecorder'
|
||||
// to avoid recursion
|
||||
return os::malloc(size, (mtNMT | otNMTRecorder));
|
||||
}
|
||||
|
||||
void* operator new(size_t size) {
|
||||
assert(false, "use nothrow version");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void operator delete(void* p) {
|
||||
os::free(p, (mtNMT | otNMTRecorder));
|
||||
}
|
||||
|
||||
// instance size
|
||||
inline size_t instance_size() const {
|
||||
return sizeof(FixedSizeMemPointerArray<E, SIZE>);
|
||||
}
|
||||
|
||||
debug_only(int capacity() const { return SIZE; })
|
||||
|
||||
public:
|
||||
// implementation of public interface
|
||||
bool out_of_memory() const { return false; }
|
||||
bool is_empty() const { return _size == 0; }
|
||||
bool is_full() { return length() >= SIZE; }
|
||||
int length() const { return _size; }
|
||||
|
||||
void clear() {
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
bool append(MemPointer* ptr) {
|
||||
if (is_full()) return false;
|
||||
_data[_size ++] = *(E*)ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool insert_at(MemPointer* p, int pos) {
|
||||
assert(false, "append only");
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool remove_at(int pos) {
|
||||
assert(false, "not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
MemPointer* at(int index) const {
|
||||
assert(index >= 0 && index < length(),
|
||||
"parameter check");
|
||||
return ((E*)&_data[index]);
|
||||
}
|
||||
|
||||
void sort(FN_SORT fn) {
|
||||
qsort((void*)_data, _size, sizeof(E), fn);
|
||||
}
|
||||
|
||||
bool shrink() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// This iterator requires pre-sorted MemPointerArray, which is sorted by:
|
||||
// 1. address
|
||||
// 2. allocation type
|
||||
// 3. sequence number
|
||||
// During the array walking, iterator collapses pointers with the same
|
||||
// address and allocation type, and only returns the one with highest
|
||||
// sequence number.
|
||||
//
|
||||
// This is read-only iterator, update methods are asserted.
|
||||
class SequencedRecordIterator : public MemPointerArrayIterator {
|
||||
private:
|
||||
MemPointerArrayIteratorImpl _itr;
|
||||
MemPointer* _cur;
|
||||
|
||||
public:
|
||||
SequencedRecordIterator(const MemPointerArray* arr):
|
||||
_itr(const_cast<MemPointerArray*>(arr)) {
|
||||
_cur = next_record();
|
||||
}
|
||||
|
||||
SequencedRecordIterator(const SequencedRecordIterator& itr):
|
||||
_itr(itr._itr) {
|
||||
_cur = next_record();
|
||||
}
|
||||
|
||||
// return the pointer at current position
|
||||
virtual MemPointer* current() const {
|
||||
return _cur;
|
||||
};
|
||||
|
||||
// return the next pointer and advance current position
|
||||
virtual MemPointer* next() {
|
||||
_cur = next_record();
|
||||
return _cur;
|
||||
}
|
||||
|
||||
// return the next pointer without advancing current position
|
||||
virtual MemPointer* peek_next() const {
|
||||
assert(false, "not implemented");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
// return the previous pointer without changing current position
|
||||
virtual MemPointer* peek_prev() const {
|
||||
assert(false, "not implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// remove the pointer at current position
|
||||
virtual void remove() {
|
||||
assert(false, "read-only iterator");
|
||||
};
|
||||
// insert the pointer at current position
|
||||
virtual bool insert(MemPointer* ptr) {
|
||||
assert(false, "read-only iterator");
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool insert_after(MemPointer* ptr) {
|
||||
assert(false, "read-only iterator");
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
// collapse the 'same kind' of records, and return this 'kind' of
|
||||
// record with highest sequence number
|
||||
MemPointer* next_record();
|
||||
|
||||
// Test if the two records are the same kind: the same memory block and allocation
|
||||
// type.
|
||||
inline bool same_kind(const MemPointerRecord* p1, const MemPointerRecord* p2) const {
|
||||
return (p1->addr() == p2->addr() &&
|
||||
(p1->flags() &MemPointerRecord::tag_masks) ==
|
||||
(p2->flags() & MemPointerRecord::tag_masks));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define DEFAULT_RECORDER_PTR_ARRAY_SIZE 512
|
||||
|
||||
class MemRecorder : public CHeapObj<mtNMT|otNMTRecorder> {
|
||||
friend class MemSnapshot;
|
||||
friend class MemTracker;
|
||||
friend class MemTrackWorker;
|
||||
|
||||
protected:
|
||||
// the array that holds memory records
|
||||
MemPointerArray* _pointer_records;
|
||||
|
||||
private:
|
||||
// used for linked list
|
||||
MemRecorder* _next;
|
||||
// active recorder can only record a certain generation data
|
||||
debug_only(unsigned long _generation;)
|
||||
|
||||
protected:
|
||||
_NOINLINE_ MemRecorder();
|
||||
~MemRecorder();
|
||||
|
||||
// record a memory operation
|
||||
bool record(address addr, MEMFLAGS flags, size_t size, address caller_pc = 0);
|
||||
|
||||
// linked list support
|
||||
inline void set_next(MemRecorder* rec) {
|
||||
_next = rec;
|
||||
}
|
||||
|
||||
inline MemRecorder* next() const {
|
||||
return _next;
|
||||
}
|
||||
|
||||
// if the recorder is full
|
||||
inline bool is_full() const {
|
||||
assert(_pointer_records != NULL, "just check");
|
||||
return _pointer_records->is_full();
|
||||
}
|
||||
|
||||
// if running out of memory when initializing recorder's internal
|
||||
// data
|
||||
inline bool out_of_memory() const {
|
||||
return (_pointer_records == NULL ||
|
||||
_pointer_records->out_of_memory());
|
||||
}
|
||||
|
||||
inline void clear() {
|
||||
assert(_pointer_records != NULL, "Just check");
|
||||
_pointer_records->clear();
|
||||
}
|
||||
|
||||
SequencedRecordIterator pointer_itr();
|
||||
|
||||
public:
|
||||
// number of MemRecorder instance
|
||||
debug_only(static volatile jint _instance_count;)
|
||||
|
||||
private:
|
||||
// sorting function, sort records into following order
|
||||
// 1. memory address
|
||||
// 2. allocation type
|
||||
// 3. sequence number
|
||||
static int sort_record_fn(const void* e1, const void* e2);
|
||||
|
||||
debug_only(void check_dup_seq(jint seq) const;)
|
||||
debug_only(void set_generation();)
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_SERVICES_MEM_RECORDER_HPP
|
Loading…
Add table
Add a link
Reference in a new issue