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