id = System.console().readLine("PID: ");
}
VirtualMachine vm = null;
try {
vm = VirtualMachine.attach(id);
String[] options = null;
int start = 0;
if (args.length > 1) {
options = args;
start = 1;
}
else {
// Show interactive menu for specifying instrumentation options.
do {
if (options != null) {
help();
}
options = System.console().readLine("OPTIONS[?]: ").split(" ");
} while (options[0].equals(""));
}
for (int i = start; i < options.length; ++i) {
s.append(' ');
s.append(options[i]);
if (options[i].startsWith("-Xoutput=")) {
file = new File(options[i].substring(9));
hasOutput = true;
}
else if (options[i].startsWith("-Xtimeout=")) {
hasTimeout = true;
}
else if (options[i].startsWith("-I")) {
hasInject = true;
}
}
if (!hasInject) {
help();
throw new IllegalArgumentException("Missing -I option");
}
// The following instructs the java agent to write to a temporary
// file if an output file has not already been specified. This is
// necessary because the java agent runs in the injectee's JVM while
// the injector runs in a separate JVM. The injectee will not be
// able to directly write the output to the injector's console.
if (!hasOutput) {
file = File.createTempFile("heapaudit",
".out");
s.append(" -Xoutput=" + file.getAbsolutePath());
}
// The following attaches to the specified process and dynamically
// injects recorders to collect heap allocation activities. The
// collection continues until the user presses enter at the command
// line. Because we are dealing with two separate JVM instances, the
// following logic relies on a file lock to signal when the
// collection should terminate.
if (!hasTimeout) {
final FileLock lock = (new FileOutputStream(file)).getChannel().lock();
(new Thread(new Runnable() {
public void run() {
try {
System.console().readLine("Press <enter> to exit HeapAudit...");
// Unblock agentmain barrier.
lock.release();
}
catch (Exception e) {
}
}
})).start();
}
try {
// Locate the current jar file path and inject itself into the
// target JVM process. NOTE: The heapaudit.jar file is intended
// to be multi-purposed. It acts as the java agent for the
// static use case, the java agent for the dynamic use case and
// also the command line utility to perform injecting the agent
// for the dynamic use case.
vm.loadAgent(HeapAudit.class.getProtectionDomain().getCodeSource().getLocation().getPath(),
s.toString());
}
catch (IOException e) {
// There is nothing wrong here. If the targeting app exits
// before agentmain exits, then an IOException will be thrown.
// The cleanup logic in agentmain is also registered as a
// shutdown hook. No need to worry about the non-terminated
// agentmain behavior.
System.out.println(" terminated");
}
// If the output file was not explicitly specified, display content
// of the temporary file generated by the injectee to the injector's
// console.
if (!hasOutput) {
BufferedReader input = new BufferedReader(new FileReader(file.getAbsolutePath()));
char[] buffer = new char[4096];
int length = 0;
while ((length = input.read(buffer)) != -1) {
System.out.println(String.valueOf(buffer,
0,
length));
}
file.delete();
}
}
catch (AttachNotSupportedException e) {
help();
throw e;
}
finally {
if (vm != null) {
vm.detach();
}
}