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