diff options
Diffstat (limited to 'tools/ahat/src/heapdump/AhatArrayInstance.java')
-rw-r--r-- | tools/ahat/src/heapdump/AhatArrayInstance.java | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/tools/ahat/src/heapdump/AhatArrayInstance.java b/tools/ahat/src/heapdump/AhatArrayInstance.java new file mode 100644 index 0000000000..d88cf94075 --- /dev/null +++ b/tools/ahat/src/heapdump/AhatArrayInstance.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ahat.heapdump; + +import com.android.tools.perflib.heap.ArrayInstance; +import com.android.tools.perflib.heap.Instance; +import java.nio.charset.StandardCharsets; +import java.util.AbstractList; +import java.util.List; + +public class AhatArrayInstance extends AhatInstance { + // To save space, we store byte, character, and object arrays directly as + // byte, character, and AhatInstance arrays respectively. This is especially + // important for large byte arrays, such as bitmaps. All other array types + // are stored as an array of objects, though we could potentially save space + // by specializing those too. mValues is a list view of the underlying + // array. + private List<Value> mValues; + private byte[] mByteArray; // null if not a byte array. + private char[] mCharArray; // null if not a char array. + + public AhatArrayInstance(long id) { + super(id); + } + + @Override void initialize(AhatSnapshot snapshot, Instance inst) { + super.initialize(snapshot, inst); + + ArrayInstance array = (ArrayInstance)inst; + switch (array.getArrayType()) { + case OBJECT: + Object[] objects = array.getValues(); + final AhatInstance[] insts = new AhatInstance[objects.length]; + for (int i = 0; i < objects.length; i++) { + if (objects[i] != null) { + Instance ref = (Instance)objects[i]; + insts[i] = snapshot.findInstance(ref.getId()); + if (ref.getNextInstanceToGcRoot() == inst) { + String field = "[" + Integer.toString(i) + "]"; + insts[i].setNextInstanceToGcRoot(this, field); + } + } + } + mValues = new AbstractList<Value>() { + @Override public int size() { + return insts.length; + } + + @Override public Value get(int index) { + AhatInstance obj = insts[index]; + return obj == null ? null : new Value(insts[index]); + } + }; + break; + + case CHAR: + final char[] chars = array.asCharArray(0, array.getLength()); + mCharArray = chars; + mValues = new AbstractList<Value>() { + @Override public int size() { + return chars.length; + } + + @Override public Value get(int index) { + return new Value(chars[index]); + } + }; + break; + + case BYTE: + final byte[] bytes = array.asRawByteArray(0, array.getLength()); + mByteArray = bytes; + mValues = new AbstractList<Value>() { + @Override public int size() { + return bytes.length; + } + + @Override public Value get(int index) { + return new Value(bytes[index]); + } + }; + break; + + default: + final Object[] values = array.getValues(); + mValues = new AbstractList<Value>() { + @Override public int size() { + return values.length; + } + + @Override public Value get(int index) { + Object obj = values[index]; + return obj == null ? null : new Value(obj); + } + }; + break; + } + } + + /** + * Returns the length of the array. + */ + public int getLength() { + return mValues.size(); + } + + /** + * Returns the array's values. + */ + public List<Value> getValues() { + return mValues; + } + + /** + * Returns the object at the given index of this array. + */ + public Value getValue(int index) { + return mValues.get(index); + } + + @Override public boolean isArrayInstance() { + return true; + } + + @Override public AhatArrayInstance asArrayInstance() { + return this; + } + + @Override public String asString(int maxChars) { + return asString(0, getLength(), maxChars); + } + + /** + * Returns the String value associated with this array. + * Only char arrays are considered as having an associated String value. + */ + String asString(int offset, int count, int maxChars) { + if (mCharArray == null) { + return null; + } + + if (count == 0) { + return ""; + } + int numChars = mCharArray.length; + if (0 <= maxChars && maxChars < count) { + count = maxChars; + } + + int end = offset + count - 1; + if (offset >= 0 && offset < numChars && end >= 0 && end < numChars) { + return new String(mCharArray, offset, count); + } + return null; + } + + /** + * Returns the ascii String value associated with this array. + * Only byte arrays are considered as having an associated ascii String value. + */ + String asAsciiString(int offset, int count, int maxChars) { + if (mByteArray == null) { + return null; + } + + if (count == 0) { + return ""; + } + int numChars = mByteArray.length; + if (0 <= maxChars && maxChars < count) { + count = maxChars; + } + + int end = offset + count - 1; + if (offset >= 0 && offset < numChars && end >= 0 && end < numChars) { + return new String(mByteArray, offset, count, StandardCharsets.US_ASCII); + } + return null; + } + + /** + * Returns the String value associated with this array. Byte arrays are + * considered as ascii encoded strings. + */ + String asMaybeCompressedString(int offset, int count, int maxChars) { + String str = asString(offset, count, maxChars); + if (str == null) { + str = asAsciiString(offset, count, maxChars); + } + return str; + } + + @Override public AhatInstance getAssociatedBitmapInstance() { + if (mByteArray != null) { + List<AhatInstance> refs = getHardReverseReferences(); + if (refs.size() == 1) { + AhatInstance ref = refs.get(0); + return ref.getAssociatedBitmapInstance(); + } + } + return null; + } + + @Override public String toString() { + String className = getClassName(); + if (className.endsWith("[]")) { + className = className.substring(0, className.length() - 2); + } + return String.format("%s[%d]@%08x", className, mValues.size(), getId()); + } + + byte[] asByteArray() { + return mByteArray; + } +} |