• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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