1/*
2 * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#ifndef SHARE_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
26#define SHARE_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
27
28#include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
29#include "jfr/utilities/jfrAllocation.hpp"
30#include "jfr/utilities/jfrTime.hpp"
31#include "jfr/utilities/jfrTypes.hpp"
32#include "memory/allocation.hpp"
33#include "oops/oop.hpp"
34#include "utilities/ticks.hpp"
35/*
36 * Handle for diagnosing Java memory leaks.
37 *
38 * The class tracks the time the object was
39 * allocated, the thread and the stack trace.
40 */
41class ObjectSample : public JfrCHeapObj {
42 friend class ObjectSampler;
43 friend class SampleList;
44 private:
45 ObjectSample* _next;
46 ObjectSample* _previous;
47 JfrCheckpointBlobHandle _thread_cp;
48 JfrCheckpointBlobHandle _klass_cp;
49 oop _object;
50 Ticks _allocation_time;
51 traceid _stack_trace_id;
52 traceid _thread_id;
53 int _index;
54 size_t _span;
55 size_t _allocated;
56 size_t _heap_used_at_last_gc;
57 unsigned int _stack_trace_hash;
58 bool _dead;
59
60 void set_dead() {
61 _dead = true;
62 }
63
64 void release_references() {
65 if (_thread_cp.valid()) {
66 _thread_cp.~JfrCheckpointBlobHandle();
67 }
68 if (_klass_cp.valid()) {
69 _klass_cp.~JfrCheckpointBlobHandle();
70 }
71 }
72
73 void reset() {
74 set_stack_trace_id(0);
75 set_stack_trace_hash(0),
76 release_references();
77 _dead = false;
78 }
79
80 public:
81 ObjectSample() : _next(NULL),
82 _previous(NULL),
83 _thread_cp(),
84 _klass_cp(),
85 _object(NULL),
86 _allocation_time(),
87 _stack_trace_id(0),
88 _thread_id(0),
89 _index(0),
90 _span(0),
91 _allocated(0),
92 _heap_used_at_last_gc(0),
93 _stack_trace_hash(0),
94 _dead(false) {}
95
96 ObjectSample* next() const {
97 return _next;
98 }
99
100 void set_next(ObjectSample* next) {
101 _next = next;
102 }
103
104 ObjectSample* prev() const {
105 return _previous;
106 }
107
108 void set_prev(ObjectSample* prev) {
109 _previous = prev;
110 }
111
112 bool is_dead() const {
113 return _dead;
114 }
115
116 const oop object() const {
117 return _object;
118 }
119
120 const oop* object_addr() const {
121 return &_object;
122 }
123
124 void set_object(oop object) {
125 _object = object;
126 }
127
128 const Klass* klass() const {
129 assert(_object != NULL, "invariant");
130 return _object->klass();
131 }
132
133 int index() const {
134 return _index;
135 }
136
137 void set_index(int index) {
138 _index = index;
139 }
140
141 size_t span() const {
142 return _span;
143 }
144
145 void set_span(size_t span) {
146 _span = span;
147 }
148
149 void add_span(size_t span) {
150 _span += span;
151 }
152
153 size_t allocated() const {
154 return _allocated;
155 }
156
157 void set_allocated(size_t size) {
158 _allocated = size;
159 }
160
161 const Ticks& allocation_time() const {
162 return _allocation_time;
163 }
164
165 const void set_allocation_time(const JfrTicks& time) {
166 _allocation_time = Ticks(time.value());
167 }
168
169 void set_heap_used_at_last_gc(size_t heap_used) {
170 _heap_used_at_last_gc = heap_used;
171 }
172
173 size_t heap_used_at_last_gc() const {
174 return _heap_used_at_last_gc;
175 }
176
177 bool has_stack_trace() const {
178 return stack_trace_id() != 0;
179 }
180
181 traceid stack_trace_id() const {
182 return _stack_trace_id;
183 }
184
185 void set_stack_trace_id(traceid id) {
186 _stack_trace_id = id;
187 }
188
189 unsigned int stack_trace_hash() const {
190 return _stack_trace_hash;
191 }
192
193 void set_stack_trace_hash(unsigned int hash) {
194 _stack_trace_hash = hash;
195 }
196
197 bool has_thread() const {
198 return _thread_id != 0;
199 }
200
201 traceid thread_id() const {
202 return _thread_id;
203 }
204
205 void set_thread_id(traceid id) {
206 _thread_id = id;
207 }
208
209 bool is_alive_and_older_than(jlong time_stamp) const {
210 return !is_dead() && (JfrTime::is_ft_enabled() ?
211 _allocation_time.ft_value() : _allocation_time.value()) < time_stamp;
212 }
213
214 const JfrCheckpointBlobHandle& thread_checkpoint() const {
215 return _thread_cp;
216 }
217
218 bool has_thread_checkpoint() const {
219 return _thread_cp.valid();
220 }
221
222 // JfrCheckpointBlobHandle assignment operator
223 // maintains proper reference counting
224 void set_thread_checkpoint(const JfrCheckpointBlobHandle& ref) {
225 if (_thread_cp != ref) {
226 _thread_cp = ref;
227 }
228 }
229
230 const JfrCheckpointBlobHandle& klass_checkpoint() const {
231 return _klass_cp;
232 }
233
234 bool has_klass_checkpoint() const {
235 return _klass_cp.valid();
236 }
237
238 void set_klass_checkpoint(const JfrCheckpointBlobHandle& ref) {
239 if (_klass_cp != ref) {
240 if (_klass_cp.valid()) {
241 _klass_cp->set_next(ref);
242 return;
243 }
244 _klass_cp = ref;
245 }
246 }
247};
248
249#endif // SHARE_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
250