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 40 private AhatBitmapInstance.BitmapDumpData mBitmapDumpData = null; 41 AhatSnapshot(SuperRoot root, Instances<AhatInstance> instances, List<AhatHeap> heaps, Site rootSite, Progress progress, Reachability retained)42 AhatSnapshot(SuperRoot root, 43 Instances<AhatInstance> instances, 44 List<AhatHeap> heaps, 45 Site rootSite, 46 Progress progress, 47 Reachability retained) { 48 mSuperRoot = root; 49 mInstances = instances; 50 mHeaps = heaps; 51 mRootSite = rootSite; 52 53 AhatInstance.computeReachability(mSuperRoot, mInstances, progress, mInstances.size()); 54 55 mBitmapDumpData = AhatBitmapInstance.findBitmapDumpData(mSuperRoot, mInstances); 56 57 for (AhatInstance inst : mInstances) { 58 // Add this instance to its site. 59 inst.getSite().addInstance(inst); 60 61 // Update registered native allocation size. 62 AhatInstance.RegisteredNativeAllocation nra = inst.asRegisteredNativeAllocation(); 63 if (nra != null) { 64 nra.referent.addRegisteredNativeSize(nra.size); 65 } 66 67 if (retained == Reachability.UNREACHABLE && inst.isUnreachable()) { 68 if (inst.getSamplePath().size() == 1) { 69 mSuperRoot.addRoot(inst); 70 } 71 } 72 } 73 74 Dominators.Graph<AhatInstance> graph = new Dominators.Graph<AhatInstance>() { 75 @Override 76 public void setDominatorsComputationState(AhatInstance node, Object state) { 77 node.setTemporaryUserData(state); 78 } 79 80 @Override 81 public Object getDominatorsComputationState(AhatInstance node) { 82 return node.getTemporaryUserData(); 83 } 84 85 @Override 86 public Iterable<AhatInstance> getReferencesForDominators(AhatInstance node) { 87 return node.getReferencesForDominators(retained); 88 } 89 90 @Override 91 public void setDominator(AhatInstance node, AhatInstance dominator) { 92 node.setDominator(dominator); 93 } 94 }; 95 new Dominators(graph).progress(progress, mInstances.size()).computeDominators(mSuperRoot); 96 97 AhatInstance.computeRetainedSize(mSuperRoot, mHeaps.size()); 98 99 for (AhatHeap heap : mHeaps) { 100 heap.addToSize(mSuperRoot.getRetainedSize(heap)); 101 } 102 103 mRootSite.prepareForUse(0, mHeaps.size(), retained); 104 } 105 106 /** 107 * Returns the instance with the given id in this snapshot. 108 * Where the id of an instance x is x.getId(). 109 * Returns null if no instance with the given id is found. 110 * 111 * @param id the id of the instance to find 112 * @return the instance with the given id 113 */ findInstance(long id)114 public AhatInstance findInstance(long id) { 115 return mInstances.get(id); 116 } 117 118 /** 119 * Returns the AhatClassObj with the given id in this snapshot. 120 * Where the id of a class object x is x.getId(). 121 * Returns null if no class object with the given id is found. 122 * 123 * @param id the id of the class object to find 124 * @return the class object with the given id 125 */ findClassObj(long id)126 public AhatClassObj findClassObj(long id) { 127 AhatInstance inst = findInstance(id); 128 return inst == null ? null : inst.asClassObj(); 129 } 130 131 /** 132 * Returns the heap with the given name. 133 * Where the name of a heap x is x.getName(). 134 * Returns null if no heap with the given name could be found. 135 * 136 * @param name the name of the heap to get 137 * @return the heap with the given name 138 */ getHeap(String name)139 public AhatHeap getHeap(String name) { 140 // We expect a small number of heaps (maybe 3 or 4 total), so a linear 141 // search should be acceptable here performance wise. 142 for (AhatHeap heap : getHeaps()) { 143 if (heap.getName().equals(name)) { 144 return heap; 145 } 146 } 147 return null; 148 } 149 150 /** 151 * Returns a list of heaps in the snapshot in canonical order. 152 * <p> 153 * Note: modifications to the returned list are visible to this 154 * AhatSnapshot, which is used by diff to insert placeholder heaps. 155 * 156 * @return list of heaps 157 */ getHeaps()158 public List<AhatHeap> getHeaps() { 159 return mHeaps; 160 } 161 162 /** 163 * Returns a collection of "rooted" instances. 164 * An instance is "rooted" if it is a GC root, or if it is retained by more 165 * than one GC root. These are reachable instances that are not immediately 166 * dominated by any other instance in the heap. 167 * 168 * @return collection of rooted instances 169 */ getRooted()170 public List<AhatInstance> getRooted() { 171 return mSuperRoot.getDominated(); 172 } 173 174 /** 175 * Returns the root allocation site for this snapshot. 176 * 177 * @return the root allocation site 178 */ getRootSite()179 public Site getRootSite() { 180 return mRootSite; 181 } 182 183 /** 184 * Returns the site associated with the given id. 185 * Where the id of a site x is x.getId(). 186 * Returns the root site if no site with the given id is found. 187 * 188 * @param id the id of the site to get 189 * @return the site with the given id 190 */ getSite(long id)191 public Site getSite(long id) { 192 Site site = mRootSite.findSite(id); 193 return site == null ? mRootSite : site; 194 } 195 setBaseline(AhatSnapshot baseline)196 void setBaseline(AhatSnapshot baseline) { 197 mBaseline = baseline; 198 } 199 200 /** 201 * Returns true if this snapshot has been diffed against a different 202 * snapshot. 203 * 204 * @return true if the snapshot has been diffed 205 */ isDiffed()206 public boolean isDiffed() { 207 return mBaseline != this; 208 } 209 getBaseline()210 @Override public AhatSnapshot getBaseline() { 211 return mBaseline; 212 } 213 isPlaceHolder()214 @Override public boolean isPlaceHolder() { 215 return false; 216 } 217 218 /** 219 * Returns duplicated bitmaps in this snapshot 220 * 221 * @return list of duplicated bitmaps 222 */ findDuplicateBitmaps()223 public List<List<AhatBitmapInstance>> findDuplicateBitmaps() { 224 return AhatBitmapInstance.findDuplicates(mBitmapDumpData); 225 } 226 } 227