Created
December 4, 2015 23:09
-
-
Save voronaam/0747c013895d0191e8f2 to your computer and use it in GitHub Desktop.
A quick implementation of the object dump query for Eclipse Memory Analizer (MAT)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.eclipse.mat.ui.snapshot.actions; | |
import java.io.BufferedOutputStream; | |
import java.io.BufferedWriter; | |
import java.io.DataOutputStream; | |
import java.io.File; | |
import java.io.FileOutputStream; | |
import java.io.OutputStreamWriter; | |
import java.io.PrintWriter; | |
import java.util.HashSet; | |
import java.util.List; | |
import org.eclipse.mat.snapshot.model.IObjectArray; | |
import org.eclipse.mat.snapshot.model.FieldDescriptor; | |
import org.eclipse.mat.snapshot.model.IClass; | |
import org.eclipse.mat.SnapshotException; | |
import org.eclipse.mat.query.IContextObject; | |
import org.eclipse.mat.query.IQuery; | |
import org.eclipse.mat.query.IResult; | |
import org.eclipse.mat.query.annotations.Argument; | |
import org.eclipse.mat.query.annotations.Argument.Advice; | |
import org.eclipse.mat.query.annotations.Icon; | |
import org.eclipse.mat.snapshot.ISnapshot; | |
import org.eclipse.mat.snapshot.model.IObject; | |
import org.eclipse.mat.snapshot.model.IPrimitiveArray; | |
import org.eclipse.mat.ui.Messages; | |
import org.eclipse.mat.util.IProgressListener; | |
import org.eclipse.mat.util.MessageUtil; | |
import org.eclipse.swt.SWT; | |
import org.eclipse.swt.widgets.Display; | |
import org.eclipse.swt.widgets.MessageBox; | |
@Icon("/icons/copy.gif") | |
public class SaveObjectToFile implements IQuery | |
{ | |
@Argument | |
public ISnapshot snapshot; | |
@Argument | |
public List<IContextObject> objects; | |
@Argument(advice = Advice.SAVE) | |
public File file; | |
@Argument(isMandatory = false) | |
public int depth = 5; | |
@Argument | |
public Display display; | |
private final HashSet<IObject> visited = new HashSet<IObject>(); | |
public int currentDepth = 0; | |
public IResult execute(IProgressListener listener) throws Exception | |
{ | |
checkIfFileExists(); | |
if (objects.size() > 1) | |
writeStringData(); | |
else if (objects.size() == 1) | |
writeRawData(); | |
// let the UI ignore this query | |
throw new IProgressListener.OperationCanceledException(); | |
} | |
private void checkIfFileExists() | |
{ | |
if (file.exists()) | |
{ | |
try | |
{ | |
// message box will popup in background... | |
Thread.sleep(500); | |
} | |
catch (InterruptedException ignore) | |
{} | |
final boolean[] goAhead = new boolean[1]; | |
display.syncExec(new Runnable() | |
{ | |
public void run() | |
{ | |
MessageBox box = new MessageBox(display.getActiveShell(), // | |
SWT.YES | SWT.NO); | |
box.setText(Messages.SaveValueAsQuery_Overwrite); | |
box.setMessage(MessageUtil.format(Messages.SaveValueAsQuery_FileExists, file.getAbsolutePath())); | |
int retValue = box.open(); | |
goAhead[0] = retValue == SWT.YES; | |
} | |
}); | |
if (!goAhead[0]) | |
throw new IProgressListener.OperationCanceledException(); | |
} | |
} | |
private void writeStringData() throws Exception | |
{ | |
FileOutputStream out = new FileOutputStream(file); | |
try | |
{ | |
PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(out, System | |
.getProperty("file.encoding")))); //$NON-NLS-1$ | |
try | |
{ | |
boolean isFirst = true; | |
for (IContextObject object : objects) | |
{ | |
if (object.getObjectId() < 0) | |
continue; | |
if (!isFirst) | |
writer.append("\n---\n"); | |
IObject subject = snapshot.getObject(object.getObjectId()); | |
writeFullData(writer, subject); | |
isFirst = false; | |
} | |
writer.flush(); | |
} | |
finally | |
{ | |
writer.close(); | |
} | |
} | |
finally | |
{ | |
out.close(); | |
} | |
} | |
private void offset(PrintWriter writer, int extra) { | |
for (int i=0; i<currentDepth * 4 + extra; i++) { | |
writer.append(' '); | |
} | |
} | |
private void writeFullData(PrintWriter writer, IObject subject) throws SnapshotException { | |
offset(writer, 0); | |
ExportInfo info = ExportInfo.of(subject); | |
if (info == null) | |
{ | |
String name = subject.getClassSpecificName(); | |
writer.append(name != null ? name : subject.getTechnicalName()); | |
writer.append("\n"); | |
if (currentDepth < depth && !visited.contains(subject)) { | |
visited.add(subject); | |
currentDepth++; | |
IClass clazz = subject.getClazz(); | |
while (clazz != null) { | |
for(FieldDescriptor field: clazz.getFieldDescriptors()) { | |
offset(writer, 2); | |
writer.append(field.getName() + " = "); | |
Object sub = subject.resolveValue(field.getName()); | |
if (sub == null) { | |
writer.append("null"); | |
} else if (sub instanceof IObjectArray) { | |
IObjectArray arr = (IObjectArray)sub; | |
writer.append("["); | |
for(long addr: arr.getReferenceArray()) { | |
if (addr == 0) continue; | |
IObject member = subject.getSnapshot().getObject(subject.getSnapshot().mapAddressToId(addr)); | |
if (member == null) { | |
writer.append("<error>"); | |
} else { | |
writeFullData(writer, member); | |
} | |
} | |
offset(writer, 2); | |
writer.append("]"); | |
} else if (sub instanceof IObject) { | |
writeFullData(writer, (IObject)sub); | |
} else { | |
writer.append("" + sub); | |
} | |
writer.append("\n"); | |
} | |
clazz = clazz.getSuperClass(); | |
} | |
currentDepth--; | |
} | |
} | |
else | |
{ | |
IPrimitiveArray charArray = info.getCharArray(); | |
final int length = charArray.getLength(); | |
final int end = info.getOffset() + info.getCount(); | |
int offset = info.getOffset(); | |
while (offset < end) | |
{ | |
int read = Math.min(4092, length - offset); | |
char[] array = (char[]) charArray.getValueArray(offset, read); | |
writer.append(new String(array)); | |
offset += read; | |
} | |
writer.append("\n"); | |
} | |
} | |
private void writeRawData() throws Exception | |
{ | |
IContextObject obj = objects.get(0); | |
if (obj.getObjectId() < 0) | |
return; | |
IObject object = snapshot.getObject(obj.getObjectId()); | |
if (!(object instanceof IPrimitiveArray)) | |
{ | |
writeStringData(); | |
return; | |
} | |
IPrimitiveArray array = (IPrimitiveArray) object; | |
FileOutputStream out = new FileOutputStream(file); | |
try | |
{ | |
DataOutputStream writer = new DataOutputStream(new BufferedOutputStream(out)); | |
try | |
{ | |
int size = array.getLength(); | |
int offset = 0; | |
while (offset < size) | |
{ | |
int read = Math.min(4092, size - offset); | |
Object valueArray = array.getValueArray(offset, read); | |
switch (array.getType()) | |
{ | |
case IObject.Type.BOOLEAN: | |
{ | |
boolean[] a = (boolean[]) valueArray; | |
for (int ii = 0; ii < a.length; ii++) | |
writer.writeBoolean(a[ii]); | |
break; | |
} | |
case IObject.Type.BYTE: | |
{ | |
byte[] a = (byte[]) valueArray; | |
writer.write(a); | |
break; | |
} | |
case IObject.Type.CHAR: | |
{ | |
char[] a = (char[]) valueArray; | |
for (int ii = 0; ii < a.length; ii++) | |
writer.writeChar(a[ii]); | |
break; | |
} | |
case IObject.Type.DOUBLE: | |
{ | |
double[] a = (double[]) valueArray; | |
for (int ii = 0; ii < a.length; ii++) | |
writer.writeDouble(a[ii]); | |
break; | |
} | |
case IObject.Type.FLOAT: | |
{ | |
float[] a = (float[]) valueArray; | |
for (int ii = 0; ii < a.length; ii++) | |
writer.writeFloat(a[ii]); | |
break; | |
} | |
case IObject.Type.INT: | |
{ | |
int[] a = (int[]) valueArray; | |
for (int ii = 0; ii < a.length; ii++) | |
writer.writeInt(a[ii]); | |
break; | |
} | |
case IObject.Type.LONG: | |
{ | |
long[] a = (long[]) valueArray; | |
for (int ii = 0; ii < a.length; ii++) | |
writer.writeLong(a[ii]); | |
break; | |
} | |
case IObject.Type.SHORT: | |
{ | |
short[] a = (short[]) valueArray; | |
for (int ii = 0; ii < a.length; ii++) | |
writer.writeShort(a[ii]); | |
break; | |
} | |
default: | |
throw new SnapshotException(MessageUtil.format( | |
Messages.SaveValueAsQuery_UnrecognizedPrimitiveArrayType, array.getType())); | |
} | |
offset += read; | |
} | |
writer.flush(); | |
} | |
finally | |
{ | |
writer.close(); | |
} | |
} | |
finally | |
{ | |
out.close(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment