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 
release_references()61   void release_references() {
62     _stacktrace.~JfrBlobHandle();
63     _thread.~JfrBlobHandle();
64     _type_set.~JfrBlobHandle();
65   }
66 
reset()67   void reset() {
68     _object = NULL;
69     set_stack_trace_id(0);
70     set_stack_trace_hash(0);
71     release_references();
72   }
73 
74  public:
ObjectSample()75   ObjectSample() : _next(NULL),
76                    _previous(NULL),
77                    _stacktrace(),
78                    _thread(),
79                    _type_set(),
80                    _object(NULL),
81                    _allocation_time(),
82                    _stack_trace_id(0),
83                    _thread_id(0),
84                    _index(0),
85                    _span(0),
86                    _allocated(0),
87                    _heap_used_at_last_gc(0),
88                    _stack_trace_hash(0) {}
89 
next() const90   ObjectSample* next() const {
91     return _next;
92   }
93 
set_next(ObjectSample * next)94   void set_next(ObjectSample* next) {
95     _next = next;
96   }
97 
prev() const98   ObjectSample* prev() const {
99     return _previous;
100   }
101 
set_prev(ObjectSample * prev)102   void set_prev(ObjectSample* prev) {
103     _previous = prev;
104   }
105 
is_dead() const106   bool is_dead() const {
107     return object() == NULL;
108   }
109 
110   const oop object() const;
111   void set_object(oop object);
112 
object_addr() const113   const oop* object_addr() const {
114     return &_object;
115   }
116 
index() const117   int index() const {
118     return _index;
119   }
120 
set_index(int index)121   void set_index(int index) {
122     _index = index;
123   }
124 
span() const125   size_t span() const {
126     return _span;
127   }
128 
set_span(size_t span)129   void set_span(size_t span) {
130     _span = span;
131   }
132 
add_span(size_t span)133   void add_span(size_t span) {
134     _span += span;
135   }
136 
allocated() const137   size_t allocated() const {
138     return _allocated;
139   }
140 
set_allocated(size_t size)141   void set_allocated(size_t size) {
142     _allocated = size;
143   }
144 
allocation_time() const145   const Ticks& allocation_time() const {
146     return _allocation_time;
147   }
148 
set_allocation_time(const JfrTicks & time)149   const void set_allocation_time(const JfrTicks& time) {
150     _allocation_time = Ticks(time.value());
151   }
152 
set_heap_used_at_last_gc(size_t heap_used)153   void set_heap_used_at_last_gc(size_t heap_used) {
154     _heap_used_at_last_gc = heap_used;
155   }
156 
heap_used_at_last_gc() const157   size_t heap_used_at_last_gc() const {
158     return _heap_used_at_last_gc;
159   }
160 
has_stack_trace_id() const161   bool has_stack_trace_id() const {
162     return stack_trace_id() != 0;
163   }
164 
stack_trace_id() const165   traceid stack_trace_id() const {
166     return _stack_trace_id;
167   }
168 
set_stack_trace_id(traceid id)169   void set_stack_trace_id(traceid id) {
170     _stack_trace_id = id;
171   }
172 
stack_trace_hash() const173   unsigned int stack_trace_hash() const {
174     return _stack_trace_hash;
175   }
176 
set_stack_trace_hash(unsigned int hash)177   void set_stack_trace_hash(unsigned int hash) {
178     _stack_trace_hash = hash;
179   }
180 
thread_id() const181   traceid thread_id() const {
182     return _thread_id;
183   }
184 
set_thread_id(traceid id)185   void set_thread_id(traceid id) {
186     _thread_id = id;
187   }
188 
is_alive_and_older_than(jlong time_stamp) const189   bool is_alive_and_older_than(jlong time_stamp) const {
190     return !is_dead() && (JfrTime::is_ft_enabled() ?
191       _allocation_time.ft_value() : _allocation_time.value()) < time_stamp;
192   }
193 
stacktrace() const194   const JfrBlobHandle& stacktrace() const {
195     return _stacktrace;
196   }
197 
has_stacktrace() const198   bool has_stacktrace() const {
199     return _stacktrace.valid();
200   }
201 
202   // JfrBlobHandle assignment operator
203   // maintains proper reference counting
set_stacktrace(const JfrBlobHandle & ref)204   void set_stacktrace(const JfrBlobHandle& ref) {
205     if (_stacktrace != ref) {
206       _stacktrace = ref;
207     }
208   }
209 
thread() const210   const JfrBlobHandle& thread() const {
211     return _thread;
212   }
213 
has_thread() const214   bool has_thread() const {
215     return _thread.valid();
216   }
217 
set_thread(const JfrBlobHandle & ref)218   void set_thread(const JfrBlobHandle& ref) {
219     if (_thread != ref) {
220       _thread = ref;
221     }
222   }
223 
type_set() const224   const JfrBlobHandle& type_set() const {
225     return _type_set;
226   }
227 
has_type_set() const228   bool has_type_set() const {
229     return _type_set.valid();
230   }
231 
set_type_set(const JfrBlobHandle & ref)232   void set_type_set(const JfrBlobHandle& ref) {
233     if (_type_set != ref) {
234       if (_type_set.valid()) {
235         _type_set->set_next(ref);
236         return;
237       }
238       _type_set = ref;
239     }
240   }
241 };
242 
243 #endif // SHARE_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
244