blob: 8ae35d24bb9a80c2e2e3b87c2ff1e2c49aaff7a4 [file] [log] [blame]
/*
* Copyright (c) 2014, 2019, 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_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
#define SHARE_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
#include "jfr/utilities/jfrAllocation.hpp"
#include "jfr/utilities/jfrBlob.hpp"
#include "jfr/utilities/jfrTime.hpp"
#include "jfr/utilities/jfrTypes.hpp"
#include "memory/allocation.hpp"
#include "oops/oop.hpp"
#include "utilities/ticks.hpp"
/*
* Handle for diagnosing Java memory leaks.
*
* The class tracks the time the object was
* allocated, the thread and the stack trace.
*/
class ObjectSample : public JfrCHeapObj {
friend class ObjectSampler;
friend class SampleList;
private:
ObjectSample* _next;
ObjectSample* _previous;
JfrBlobHandle _stacktrace;
JfrBlobHandle _thread;
JfrBlobHandle _type_set;
oop _object;
Ticks _allocation_time;
traceid _stack_trace_id;
traceid _thread_id;
int _index;
size_t _span;
size_t _allocated;
size_t _heap_used_at_last_gc;
unsigned int _stack_trace_hash;
bool _dead;
void set_dead() {
_dead = true;
}
void release_references() {
_stacktrace.~JfrBlobHandle();
_thread.~JfrBlobHandle();
_type_set.~JfrBlobHandle();
}
void reset() {
set_stack_trace_id(0);
set_stack_trace_hash(0);
release_references();
_dead = false;
}
public:
ObjectSample() : _next(NULL),
_previous(NULL),
_stacktrace(),
_thread(),
_type_set(),
_object(NULL),
_allocation_time(),
_stack_trace_id(0),
_thread_id(0),
_index(0),
_span(0),
_allocated(0),
_heap_used_at_last_gc(0),
_stack_trace_hash(0),
_dead(false) {}
ObjectSample* next() const {
return _next;
}
void set_next(ObjectSample* next) {
_next = next;
}
ObjectSample* prev() const {
return _previous;
}
void set_prev(ObjectSample* prev) {
_previous = prev;
}
bool is_dead() const {
return _dead;
}
const oop object() const {
return _object;
}
const oop* object_addr() const {
return &_object;
}
void set_object(oop object) {
_object = object;
}
const Klass* klass() const {
assert(_object != NULL, "invariant");
return _object->klass();
}
int index() const {
return _index;
}
void set_index(int index) {
_index = index;
}
size_t span() const {
return _span;
}
void set_span(size_t span) {
_span = span;
}
void add_span(size_t span) {
_span += span;
}
size_t allocated() const {
return _allocated;
}
void set_allocated(size_t size) {
_allocated = size;
}
const Ticks& allocation_time() const {
return _allocation_time;
}
const void set_allocation_time(const JfrTicks& time) {
_allocation_time = Ticks(time.value());
}
void set_heap_used_at_last_gc(size_t heap_used) {
_heap_used_at_last_gc = heap_used;
}
size_t heap_used_at_last_gc() const {
return _heap_used_at_last_gc;
}
bool has_stack_trace_id() const {
return stack_trace_id() != 0;
}
traceid stack_trace_id() const {
return _stack_trace_id;
}
void set_stack_trace_id(traceid id) {
_stack_trace_id = id;
}
unsigned int stack_trace_hash() const {
return _stack_trace_hash;
}
void set_stack_trace_hash(unsigned int hash) {
_stack_trace_hash = hash;
}
traceid thread_id() const {
return _thread_id;
}
void set_thread_id(traceid id) {
_thread_id = id;
}
bool is_alive_and_older_than(jlong time_stamp) const {
return !is_dead() && (JfrTime::is_ft_enabled() ?
_allocation_time.ft_value() : _allocation_time.value()) < time_stamp;
}
const JfrBlobHandle& stacktrace() const {
return _stacktrace;
}
bool has_stacktrace() const {
return _stacktrace.valid();
}
// JfrBlobHandle assignment operator
// maintains proper reference counting
void set_stacktrace(const JfrBlobHandle& ref) {
if (_stacktrace != ref) {
_stacktrace = ref;
}
}
const JfrBlobHandle& thread() const {
return _thread;
}
bool has_thread() const {
return _thread.valid();
}
void set_thread(const JfrBlobHandle& ref) {
if (_thread != ref) {
_thread = ref;
}
}
const JfrBlobHandle& type_set() const {
return _type_set;
}
bool has_type_set() const {
return _type_set.valid();
}
void set_type_set(const JfrBlobHandle& ref) {
if (_type_set != ref) {
if (_type_set.valid()) {
_type_set->set_next(ref);
return;
}
_type_set = ref;
}
}
};
#endif // SHARE_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP