1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ahat.heapdump; 18 19 import com.android.ahat.dominators.Dominators; 20 import com.android.ahat.progress.Progress; 21 import java.util.List; 22 23 /** 24 * A parsed heap dump. 25 * It contains methods to access the heaps, allocation sites, roots, classes, 26 * and instances from the parsed heap dump. 27 */ 28 public class AhatSnapshot implements Diffable<AhatSnapshot> { 29 private final Site mRootSite; 30 31 private final SuperRoot mSuperRoot; 32 33 // List of all ahat instances. 34 private final Instances<AhatInstance> mInstances; 35 36 private List<AhatHeap> mHeaps; 37 38 private AhatSnapshot mBaseline = this; 39 AhatSnapshot(SuperRoot root, Instances<AhatInstance> instances, List<AhatHeap> heaps, Site rootSite, Progress progress, Reachability retained)40 AhatSnapshot(SuperRoot root, 41 Instances<AhatInstance> instances, 42 List<AhatHeap> heaps, 43 Site rootSite, 44 Progress progress, 45 Reachability retained) { 46 mSuperRoot = root; 47 mInstances = instances; 48 mHeaps = heaps; 49 mRootSite = rootSite; 50 51 AhatInstance.computeReachability(mSuperRoot, progress, mInstances.size()); 52 53 for (AhatInstance inst : mInstances) { 54 // Add this instance to its site. 55 inst.getSite().addInstance(inst); 56 57 // Update registered native allocation size. 58 AhatInstance.RegisteredNativeAllocation nra = inst.asRegisteredNativeAllocation(); 59 if (nra != null) { 60 nra.referent.addRegisteredNativeSize(nra.size); 61 } 62 63 if (retained == Reachability.UNREACHABLE && inst.isUnreachable()) { 64 mSuperRoot.addRoot(inst); 65 } 66 } 67 68 Dominators.Graph<AhatInstance> graph = new Dominators.Graph<AhatInstance>() { 69 @Override 70 public void setDominatorsComputationState(AhatInstance node, Object state) { 71 node.setTemporaryUserData(state); 72 } 73 74 @Override 75 public Object getDominatorsComputationState(AhatInstance node) { 76 return node.getTemporaryUserData(); 77 } 78 79 @Override 80 public Iterable<AhatInstance> getReferencesForDominators(AhatInstance node) { 81 return node.getReferencesForDominators(retained); 82 } 83 84 @Override 85 public void setDominator(AhatInstance node, AhatInstance dominator) { 86 node.setDominator(dominator); 87 } 88 }; 89 new Dominators(graph).progress(progress, mInstances.size()).computeDominators(mSuperRoot); 90 91 AhatInstance.computeRetainedSize(mSuperRoot, mHeaps.size()); 92 93 for (AhatHeap heap : mHeaps) { 94 heap.addToSize(mSuperRoot.getRetainedSize(heap)); 95 } 96 97 mRootSite.prepareForUse(0, mHeaps.size(), retained); 98 } 99 100 /** 101 * Returns the instance with the given id in this snapshot. 102 * Where the id of an instance x is x.getId(). 103 * Returns null if no instance with the given id is found. 104 * 105 * @param id the id of the instance to find 106 * @return the instance with the given id 107 */ findInstance(long id)108 public AhatInstance findInstance(long id) { 109 return mInstances.get(id); 110 } 111 112 /** 113 * Returns the AhatClassObj with the given id in this snapshot. 114 * Where the id of a class object x is x.getId(). 115 * Returns null if no class object with the given id is found. 116 * 117 * @param id the id of the class object to find 118 * @return the class object with the given id 119 */ findClassObj(long id)120 public AhatClassObj findClassObj(long id) { 121 AhatInstance inst = findInstance(id); 122 return inst == null ? null : inst.asClassObj(); 123 } 124 125 /** 126 * Returns the heap with the given name. 127 * Where the name of a heap x is x.getName(). 128 * Returns null if no heap with the given name could be found. 129 * 130 * @param name the name of the heap to get 131 * @return the heap with the given name 132 */ getHeap(String name)133 public AhatHeap getHeap(String name) { 134 // We expect a small number of heaps (maybe 3 or 4 total), so a linear 135 // search should be acceptable here performance wise. 136 for (AhatHeap heap : getHeaps()) { 137 if (heap.getName().equals(name)) { 138 return heap; 139 } 140 } 141 return null; 142 } 143 144 /** 145 * Returns a list of heaps in the snapshot in canonical order. 146 * <p> 147 * Note: modifications to the returned list are visible to this 148 * AhatSnapshot, which is used by diff to insert placeholder heaps. 149 * 150 * @return list of heaps 151 */ getHeaps()152 public List<AhatHeap> getHeaps() { 153 return mHeaps; 154 } 155 156 /** 157 * Returns a collection of "rooted" instances. 158 * An instance is "rooted" if it is a GC root, or if it is retained by more 159 * than one GC root. These are reachable instances that are not immediately 160 * dominated by any other instance in the heap. 161 * 162 * @return collection of rooted instances 163 */ getRooted()164 public List<AhatInstance> getRooted() { 165 return mSuperRoot.getDominated(); 166 } 167 168 /** 169 * Returns the root allocation site for this snapshot. 170 * 171 * @return the root allocation site 172 */ getRootSite()173 public Site getRootSite() { 174 return mRootSite; 175 } 176 177 /** 178 * Returns the site associated with the given id. 179 * Where the id of a site x is x.getId(). 180 * Returns the root site if no site with the given id is found. 181 * 182 * @param id the id of the site to get 183 * @return the site with the given id 184 */ getSite(long id)185 public Site getSite(long id) { 186 Site site = mRootSite.findSite(id); 187 return site == null ? mRootSite : site; 188 } 189 setBaseline(AhatSnapshot baseline)190 void setBaseline(AhatSnapshot baseline) { 191 mBaseline = baseline; 192 } 193 194 /** 195 * Returns true if this snapshot has been diffed against a different 196 * snapshot. 197 * 198 * @return true if the snapshot has been diffed 199 */ isDiffed()200 public boolean isDiffed() { 201 return mBaseline != this; 202 } 203 getBaseline()204 @Override public AhatSnapshot getBaseline() { 205 return mBaseline; 206 } 207 isPlaceHolder()208 @Override public boolean isPlaceHolder() { 209 return false; 210 } 211 } 212