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/utilities/jfrAllocation.hpp"
29 #include "jfr/utilities/jfrBlob.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 /*
37  * Handle for diagnosing Java memory leaks.
38  *
39  * The class tracks the time the object was
40  * allocated, the thread and the stack trace.
41  */
42 class ObjectSample : public JfrCHeapObj {
43   friend class ObjectSampler;
44   friend class SampleList;
45  private:
46   ObjectSample* _next;
47   ObjectSample* _previous;
48   JfrBlobHandle _stacktrace;
49   JfrBlobHandle _thread;
50   JfrBlobHandle _type_set;
51   oop _object;
52   Ticks _allocation_time;
53   traceid _stack_trace_id;
54   traceid _thread_id;
55   int _index;
56   size_t _span;
57   size_t _allocated;
58   size_t _heap_used_at_last_gc;
59   unsigned int _stack_trace_hash;
60   bool _dead;
61 
set_dead()62   void set_dead() {
63     _dead = true;
64   }
65 
release_references()66   void release_references() {
67     _stacktrace.~JfrBlobHandle();
68     _thread.~JfrBlobHandle();
69     _type_set.~JfrBlobHandle();
70   }
71 
reset()72   void reset() {
73     set_stack_trace_id(0);
74     set_stack_trace_hash(0);
75     release_references();
76     _dead = false;
77   }
78 
79  public:
ObjectSample()80   ObjectSample() : _next(NULL),
81                    _previous(NULL),
82                    _stacktrace(),
83                    _thread(),
84                    _type_set(),
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 
next() const96   ObjectSample* next() const {
97     return _next;
98   }
99 
set_next(ObjectSample * next)100   void set_next(ObjectSample* next) {
101     _next = next;
102   }
103 
prev() const104   ObjectSample* prev() const {
105     return _previous;
106   }
107 
set_prev(ObjectSample * prev)108   void set_prev(ObjectSample* prev) {
109     _previous = prev;
110   }
111 
is_dead() const112   bool is_dead() const {
113     return _dead;
114   }
115 
object() const116   const oop object() const {
117     return _object;
118   }
119 
object_addr() const120   const oop* object_addr() const {
121     return &_object;
122   }
123 
set_object(oop object)124   void set_object(oop object) {
125     _object = object;
126   }
127 
klass() const128   const Klass* klass() const {
129     assert(_object != NULL, "invariant");
130     return _object->klass();
131   }
132 
index() const133   int index() const {
134     return _index;
135   }
136 
set_index(int index)137   void set_index(int index) {
138     _index = index;
139   }
140 
span() const141   size_t span() const {
142     return _span;
143   }
144 
set_span(size_t span)145   void set_span(size_t span) {
146     _span = span;
147   }
148 
add_span(size_t span)149   void add_span(size_t span) {
150     _span += span;
151   }
152 
allocated() const153   size_t allocated() const {
154     return _allocated;
155   }
156 
set_allocated(size_t size)157   void set_allocated(size_t size) {
158     _allocated = size;
159   }
160 
allocation_time() const161   const Ticks& allocation_time() const {
162     return _allocation_time;
163   }
164 
set_allocation_time(const JfrTicks & time)165   const void set_allocation_time(const JfrTicks& time) {
166     _allocation_time = Ticks(time.value());
167   }
168 
set_heap_used_at_last_gc(size_t heap_used)169   void set_heap_used_at_last_gc(size_t heap_used) {
170     _heap_used_at_last_gc = heap_used;
171   }
172 
heap_used_at_last_gc() const173   size_t heap_used_at_last_gc() const {
174     return _heap_used_at_last_gc;
175   }
176 
has_stack_trace_id() const177   bool has_stack_trace_id() const {
178     return stack_trace_id() != 0;
179   }
180 
stack_trace_id() const181   traceid stack_trace_id() const {
182     return _stack_trace_id;
183   }
184 
set_stack_trace_id(traceid id)185   void set_stack_trace_id(traceid id) {
186     _stack_trace_id = id;
187   }
188 
stack_trace_hash() const189   unsigned int stack_trace_hash() const {
190     return _stack_trace_hash;
191   }
192 
set_stack_trace_hash(unsigned int hash)193   void set_stack_trace_hash(unsigned int hash) {
194     _stack_trace_hash = hash;
195   }
196 
thread_id() const197   traceid thread_id() const {
198     return _thread_id;
199   }
200 
set_thread_id(traceid id)201   void set_thread_id(traceid id) {
202     _thread_id = id;
203   }
204 
is_alive_and_older_than(jlong time_stamp) const205   bool is_alive_and_older_than(jlong time_stamp) const {
206     return !is_dead() && (JfrTime::is_ft_enabled() ?
207       _allocation_time.ft_value() : _allocation_time.value()) < time_stamp;
208   }
209 
stacktrace() const210   const JfrBlobHandle& stacktrace() const {
211     return _stacktrace;
212   }
213 
has_stacktrace() const214   bool has_stacktrace() const {
215     return _stacktrace.valid();
216   }
217 
218   // JfrBlobHandle assignment operator
219   // maintains proper reference counting
set_stacktrace(const JfrBlobHandle & ref)220   void set_stacktrace(const JfrBlobHandle& ref) {
221     if (_stacktrace != ref) {
222       _stacktrace = ref;
223     }
224   }
225 
thread() const226   const JfrBlobHandle& thread() const {
227     return _thread;
228   }
229 
has_thread() const230   bool has_thread() const {
231     return _thread.valid();
232   }
233 
set_thread(const JfrBlobHandle & ref)234   void set_thread(const JfrBlobHandle& ref) {
235     if (_thread != ref) {
236       _thread = ref;
237     }
238   }
239 
type_set() const240   const JfrBlobHandle& type_set() const {
241     return _type_set;
242   }
243 
has_type_set() const244   bool has_type_set() const {
245     return _type_set.valid();
246   }
247 
set_type_set(const JfrBlobHandle & ref)248   void set_type_set(const JfrBlobHandle& ref) {
249     if (_type_set != ref) {
250       if (_type_set.valid()) {
251         _type_set->set_next(ref);
252         return;
253       }
254       _type_set = ref;
255     }
256   }
257 };
258 
259 #endif // SHARE_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
260