com.facebook.presto.jdbc.internal.jol.heap.HeapDumpReader Maven / Gradle / Ivy
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.facebook.presto.jdbc.internal.jol.heap;
import com.facebook.presto.jdbc.internal.jol.info.ClassData;
import com.facebook.presto.jdbc.internal.jol.info.FieldData;
import com.facebook.presto.jdbc.internal.jol.util.Multiset;
import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
/**
* Experimental heap dump reader
*
* @author Aleksey Shipilev
*/
public class HeapDumpReader {
private final InputStream is;
private final Map strings;
private final Map classNames;
private final Multiset classCounts;
private final Map classDatas;
private int idSize;
private int readBytes;
private final byte[] buf;
private final ByteBuffer wrapBuf;
public HeapDumpReader(File file) throws FileNotFoundException {
this.is = new BufferedInputStream(new FileInputStream(file));
this.strings = new HashMap();
this.classNames = new HashMap();
this.classCounts = new Multiset();
this.classDatas = new HashMap();
this.buf = new byte[4096];
this.wrapBuf = ByteBuffer.wrap(buf);
}
private int read() throws IOException {
int v = is.read();
if (v != -1) {
readBytes++;
return v;
} else {
throw new EOFException();
}
}
private int read(byte[] b, int size) throws IOException {
int read = is.read(b, 0, size);
readBytes += read;
return read;
}
public Multiset parse() throws IOException {
readNullTerminated(); // header
idSize = read_U4();
read_U4(); // timestamp, lo
read_U4(); // timestamp, hi
while (true) {
if (is.available() == 0) break;
int tag = read_U1();
read_U4(); // relative time
int len = read_U4();
int lastCount = readBytes;
switch (tag) {
case 0x01: {
long id = read_ID();
String s = readString(len - idSize);
strings.put(id, s);
break;
}
case 0x02: {
read_U4(); // serial
long id = read_ID();
read_U4(); // stack trace
long nameID = read_ID();
classNames.put(id, strings.get(nameID));
break;
}
case 0x0C:
case 0x1C:
while (readBytes - lastCount < len) {
digestHeapDump();
}
break;
default:
read_null(len);
}
if (readBytes - lastCount != len) {
throw new IllegalStateException("Expected to read " + len + " bytes, but read " + (readBytes - lastCount) + " bytes");
}
}
return classCounts;
}
private void digestHeapDump() throws IOException {
int subTag = read_U1();
switch (subTag) {
case 0x01:
read_ID();
read_ID();
return;
case 0x02:
read_ID();
read_U4();
read_U4();
return;
case 0x03:
read_ID();
read_U4();
read_U4();
return;
case 0x04:
read_ID();
read_U4();
return;
case 0x05:
read_ID();
return;
case 0x06:
read_ID();
read_U4();
return;
case 0x07:
read_ID();
return;
case 0x08:
read_ID();
read_U4();
read_U4();
return;
case 0x20:
digestClass();
return;
case 0x21:
digestInstance();
return;
case 0x22:
digestObjArray();
return;
case 0x23:
digestPrimArray();
return;
default:
throw new IllegalStateException("Unknown subtag: " + subTag);
}
}
private void digestPrimArray() throws IOException {
read_ID(); // array id
read_U4(); // stack trace
int elements = read_U4();
int typeClass = read_U1();
read_null(elements * getSize(typeClass));
classCounts.add(new ClassData(getTypeString(typeClass) + "[]", getTypeString(typeClass), elements));
}
private void digestObjArray() throws IOException {
read_ID(); // array id
read_U4(); // stack trace
int elements = read_U4();
read_ID(); // type class
read_null(elements * idSize);
// assume Object, we don't care about the exact types here
classCounts.add(new ClassData("Object[]", "Object", elements));
}
private void digestInstance() throws IOException {
read_ID(); // object id
read_U4(); // stack trace
long klassID = read_ID();
classCounts.add(classDatas.get(klassID));
int instanceBytes = read_U4();
read_null(instanceBytes);
}
private void digestClass() throws IOException {
long klassID = read_ID();
String name = classNames.get(klassID);
ClassData cd = new ClassData(name);
cd.addSuperClass(name);
read_U4(); // stack trace
long superKlassID = read_ID();
ClassData superCd = classDatas.get(superKlassID);
if (superCd != null) {
cd.merge(superCd);
}
read_ID(); // class loader
read_ID(); // signers
read_ID(); // protection domain
read_ID(); // reserved
read_ID(); // reserved
read_U4(); // instance size
int cpCount = read_U2();
for (int c = 0; c < cpCount; c++) {
read_U2(); // cp index
int type = read_U1(); // cp type
readValue(type); // value
}
int cpStatics = read_U2();
for (int c = 0; c < cpStatics; c++) {
read_ID(); // index
int type = read_U1(); // type
readValue(type); // value
}
int cpInstance = read_U2();
for (int c = 0; c < cpInstance; c++) {
long index = read_ID();
int type = read_U1();
cd.addField(FieldData.create(name, strings.get(index), getTypeString(type)));
}
classDatas.put(klassID, cd);
}
private long readValue(int type) throws IOException {
int size = getSize(type);
switch (size) {
case 1:
return read_U1();
case 2:
return read_U2();
case 4:
return read_U4();
case 8:
return read_U8();
default:
throw new IllegalStateException("Unknown size: " + size);
}
}
private int getSize(int type) throws IOException {
switch (type) {
case 2: // object
if (idSize == 4)
return 4;
if (idSize == 8)
return 8;
throw new IllegalStateException();
case 4: // boolean
case 8: // byte
return 1;
case 9: // short
case 5: // char
return 2;
case 10: // int
case 6: // float
return 4;
case 7: // double
case 11: // long
return 8;
default:
throw new IllegalStateException("Unknown type: " + type);
}
}
private String getTypeString(int type) throws IOException {
switch (type) {
case 2:
return "Object"; // TODO: Read the exact type;
case 4:
return "boolean";
case 8:
return "byte";
case 9:
return "short";
case 5:
return "char";
case 10:
return "int";
case 6:
return "float";
case 7:
return "double";
case 11:
return "long";
default:
throw new IllegalStateException("Unknown type: " + type);
}
}
private long read_ID() throws IOException {
int read = read(buf, idSize);
if (read == idSize) {
if (idSize <= 4) {
return wrapBuf.get(0);
} else {
return wrapBuf.getLong(0);
}
}
throw new IllegalStateException("Unable to read 1 bytes");
}
void read_null(int len) throws IOException {
int rem = len;
int read;
do {
read = read(buf, Math.min(buf.length, rem));
rem -= read;
} while (rem > 0);
}
String readNullTerminated() throws IOException {
int r;
StringBuilder sb = new StringBuilder();
while ((r = read()) != -1) {
if (r == 0) break;
sb.append((char) (r & 0xFF));
}
return sb.toString();
}
String readString(int len) throws IOException {
StringBuilder sb = new StringBuilder();
for (int l = 0; l < len; l++) {
int r = read();
if (r == -1) break;
sb.append((char) (r & 0xFF));
}
return sb.toString();
}
long read_U8() throws IOException {
int read = read(buf, 8);
if (read == 8) {
return wrapBuf.getLong(0);
}
throw new IllegalStateException("Unable to read 8 bytes");
}
int read_U4() throws IOException {
int read = read(buf, 4);
if (read == 4) {
return wrapBuf.getInt(0);
}
throw new IllegalStateException("Unable to read 4 bytes");
}
int read_U2() throws IOException {
int read = read(buf, 2);
if (read == 2) {
return wrapBuf.getShort(0);
}
throw new IllegalStateException("Unable to read 2 bytes");
}
int read_U1() throws IOException {
int read = read(buf, 1);
if (read == 1) {
return wrapBuf.get(0);
}
throw new IllegalStateException("Unable to read 1 bytes");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy