1 /* 2 * Copyright (c) 2014, 2018, 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_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP 26 #define SHARE_VM_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 */ 41 class 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_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP