Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions DuplicatedBitmapAnalyzer/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
apply plugin: 'java'



version 1.0

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.squareup.haha:haha:2.0.4'
}


Expand All @@ -15,6 +14,14 @@ jar {
attributes 'Manifest-Version': version
}

sourceSets{
main{
java{
srcDir 'src'
}
}
}

from {
exclude 'META-INF/MANIFEST.MF'
exclude 'META-INF/*.SF'
Expand Down
96 changes: 93 additions & 3 deletions DuplicatedBitmapAnalyzer/src/com/hprof/bitmap/Main.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,103 @@
package com.hprof.bitmap;

import java.io.FileInputStream;
import com.hprof.bitmap.entry.BitmapInstance;
import com.hprof.bitmap.entry.DuplicatedCollectInfo;
import com.hprof.bitmap.utils.HahaHelper;
import com.squareup.haha.perflib.ArrayInstance;
import com.squareup.haha.perflib.ClassInstance;
import com.squareup.haha.perflib.ClassObj;
import com.squareup.haha.perflib.Heap;
import com.squareup.haha.perflib.HprofParser;
import com.squareup.haha.perflib.Instance;
import com.squareup.haha.perflib.Snapshot;
import com.squareup.haha.perflib.io.HprofBuffer;
import com.squareup.haha.perflib.io.MemoryMappedFileBuffer;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class Main {

public static void main(String[] args) throws IOException {
File heapDumpFile = new File("./myhprof.hprof");

boolean isExists = heapDumpFile.exists();
System.out.println("heapDumpFile is exists:" + isExists);

HprofBuffer buffer = new MemoryMappedFileBuffer(heapDumpFile);
HprofParser parser = new HprofParser(buffer);
Snapshot snapshot = parser.parse();
snapshot.computeDominators();

ClassObj bitmapClass = snapshot.findClass("android.graphics.Bitmap");

// 只分析 default 和 app
Heap defaultHeap = snapshot.getHeap("default");
Heap appHeap = snapshot.getHeap("app");
// 从 heap 中获取 bitmap instance 实例
List<Instance> defaultBmInstance = bitmapClass.getHeapInstances(defaultHeap.getId());
List<Instance> appBmInstance = bitmapClass.getHeapInstances(appHeap.getId());
defaultBmInstance.addAll(appBmInstance);

List<DuplicatedCollectInfo> collectInfos = collectSameBitmap(snapshot, defaultBmInstance);
for (DuplicatedCollectInfo info : collectInfos) {
println(info.string());
}
}

private static List<DuplicatedCollectInfo> collectSameBitmap(Snapshot snapshot, List<Instance> bmInstanceList) {
Map<String, List<Instance>> collectSameMap = new HashMap<>();
ArrayList<DuplicatedCollectInfo> duplicatedCollectInfos = new ArrayList<>();

// 收集
for (Instance instance : bmInstanceList) {
List<ClassInstance.FieldValue> classFieldList = HahaHelper.classInstanceValues(instance);

ArrayInstance arrayInstance = HahaHelper.fieldValue(classFieldList, "mBuffer");
byte[] mBufferByte = HahaHelper.getByteArray(arrayInstance);
int mBufferHashCode = Arrays.hashCode(mBufferByte);
String hashKey = String.valueOf(mBufferHashCode);

if (collectSameMap.containsKey(hashKey)) {
collectSameMap.get(hashKey).add(instance);
} else {
List<Instance> bmList = new ArrayList<>();
bmList.add(instance);
collectSameMap.put(hashKey, bmList);
}

}

// 去除只有一例的
Iterator<Map.Entry<String, List<Instance>>> it = collectSameMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, List<Instance>> entry = it.next();
if (entry.getValue().size() <= 1) {
it.remove();
}
}

// 留下重复的图片,创建 duplicatedCollectInfo 对象存入数组中
for (Map.Entry<String, List<Instance>> entry : collectSameMap.entrySet()) {
DuplicatedCollectInfo info = new DuplicatedCollectInfo(entry.getKey());
for (Instance instance : entry.getValue()) {
info.addBitmapInstance(new BitmapInstance(snapshot,entry.getKey(), instance));
}
info.internalSetValue();
duplicatedCollectInfos.add(info);
}

return duplicatedCollectInfos;
}


private static void println(String content) {
System.out.println(content);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.hprof.bitmap.entry;

import com.hprof.bitmap.utils.HahaHelper;
import com.hprof.bitmap.utils.TraceUtils;
import com.squareup.haha.perflib.ArrayInstance;
import com.squareup.haha.perflib.ClassInstance;
import com.squareup.haha.perflib.ClassObj;
import com.squareup.haha.perflib.Instance;
import com.squareup.haha.perflib.Snapshot;
import com.squareup.leakcanary.AnalysisResult;
import com.squareup.leakcanary.AnalyzerProgressListener;
import com.squareup.leakcanary.ExcludedRefs;
import com.squareup.leakcanary.HeapAnalyzer;
import com.squareup.leakcanary.Reachability;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* @author Zengshaoyi
* @version 1.0 <p><strong>Features draft description.主要功能介绍</strong></p>
* @since 2018/12/26 15:35
*/
public class BitmapInstance {

private String mHash;

private Instance mInstance;

private ArrayList<Instance> mTraceStack = new ArrayList<>();

private int mWith;

private int mHeight;

private int size;

private Snapshot mSnapshot;

public BitmapInstance(Snapshot snapshot, String hash, Instance instance) {
mSnapshot = snapshot;
mHash = hash;
mInstance = instance;
mTraceStack.addAll(TraceUtils.getTraceFromInstance(mInstance));

List<ClassInstance.FieldValue> classFieldList = HahaHelper.classInstanceValues(instance);
mWith = HahaHelper.fieldValue(classFieldList, "mWidth");
mHeight = HahaHelper.fieldValue(classFieldList, "mHeight");

ArrayInstance arrayInstance = HahaHelper.fieldValue(classFieldList, "mBuffer");
byte[] mBufferByte = HahaHelper.getByteArray(arrayInstance);
if (mBufferByte != null) {
size = mBufferByte.length;
}
}

public String getHash() {
return mHash;
}

public Instance getInstance() {
return mInstance;
}

public String getTrace() {
StringBuilder builder = new StringBuilder();
builder.append("[");
for (int i = 0; i < mTraceStack.size(); i++) {
String className;
if (mTraceStack.get(i) instanceof ClassObj) {
className = ((ClassObj) mTraceStack.get(i)).getClassName();
} else {
className = mTraceStack.get(i).getClassObj().getClassName();
}

builder.append("\"").append(className).append("\"");
if (i != mTraceStack.size() - 1) {
builder.append(",");
}else{
builder.append("]");
}
builder.append("\n");
}
return builder.toString();
}

public String getTraceFromLeakCanary(){
HeapAnalyzer analyzer = new HeapAnalyzer(ExcludedRefs.builder().build(),AnalyzerProgressListener.NONE,
Collections.<Class<? extends Reachability.Inspector>>emptyList());


AnalysisResult ar = analyzer.findLeakTrace(System.nanoTime(), mSnapshot, mInstance,true);
return ar.leakTrace.toString();
}

public int getWith() {
return mWith;
}

public int getHeight() {
return mHeight;
}

public int getSize() {
return size;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.hprof.bitmap.entry;

import java.util.ArrayList;

/**
* @author Zengshaoyi
* @version 1.0 <p><strong>Features draft description.主要功能介绍</strong></p>
* @since 2018/12/26 15:50
*/
public class DuplicatedCollectInfo {

// hash
private String mHash;

// 相同 hash 的 Bitmap
private ArrayList<BitmapInstance> mBitmapInstances = new ArrayList<>();

// mBitmapInstances size
private int duplicatedCount;

private int size;

private int width;

private int height;

public DuplicatedCollectInfo(String hash) {
this.mHash = hash;
}

public void addBitmapInstance(BitmapInstance bitmapInstance) {
mBitmapInstances.add(bitmapInstance);
}

public void internalSetValue() {
duplicatedCount = mBitmapInstances.size();
if(mBitmapInstances.size() > 0){
BitmapInstance instance = mBitmapInstances.get(0);
this.width = instance.getWith();
this.height = instance.getHeight();
this.size = instance.getSize();
}
}

public String string() {
StringBuilder builder = new StringBuilder();
builder.append("{\n")
.append("\t\"hash\":").append(mHash).append(",\n")
.append("\t\"size\":").append(size).append(",\n")
.append("\t\"width\":").append(width).append(",\n")
.append("\t\"height\":").append(height).append(",\n")
.append("\t\"duplicatedCount\":").append(duplicatedCount).append(",\n")
.append("\t\"stack\":").append("[\n");

for(int i=0;i<mBitmapInstances.size();i++){
builder.append(mBitmapInstances.get(i).getTraceFromLeakCanary());
if(i != mBitmapInstances.size() -1 ){
builder.append(",\n");
}
}

builder.append("]\n")
.append("}\n");
return builder.toString();
}
}
Loading