105
Chapter - 1 Java Tools Terminology Certificate: A digitally signed statement from the issuer saying that the public key of the subject has some specific value. Certificate Chain: A series of certificates that one certificate signs the public key of the issuer of the next certificate. Usually the top certificate (the first certificate) is self-signed, where issuer signed its own public key. JAR (Java Archive): A platform-independent file format that aggregates many files into one. Multiple Java applets and their requisite components (.class files, images and sounds) can be bundled in a JAR file and subsequently downloaded to a browser in a single HTTP transaction, greatly improving the download speed. The JAR format also supports compression, which reduces the file size, further improving the download time. In addition, the applet author can digitally sign individual entries in a JAR file to authenticate their origin. It is fully extensible. "jar": A command line tool for managing JAR files. "jar" is distributed as part of the JDK package from Sun. "java": The Java launcher - A command line tool to launch Java applications. "java" is distributed as part of the JDK package from Sun. "javac": The Java compier - A command line tool to compile Java source files. "javac" is distributed as part of the JDK package from Sun. "javap": The Java Class File Disassembler - A command line tool that reads Java bytecode class files and disassembles them. "jdb": The Java Debugger - A command line tool to debug Java applications. "jdb" is distributed as part of the JDK package from Sun. "JDI (Java Debug Interface)": A high level Java API providing information useful for debuggers and similar systems needing access to the running state of a (usually remote) virtual machine. "JPDA (Java Platform Debugger Architecture)": An infrastructure that allows user to build end-user debugger applications. It includes the following three-layered APIs: Java Debug Interface (JDI), a high-level Java programming language interface, including support for remote debugging; Java Debug Wire Protocol (JDWP), which defines the format of information and requests transferred between the debugging process and the debugger front end; The JVM(TM) Tools Interface, JVM TI. This is a low-level native interface that defines the services a Java virtual machine provides for tools, including debugging. JVM TI is new in J2SE 5.0 and replaces JVMDI and JVMPI, both of which are deprecated and will be removed in a future release. "JVM (Java Virtual Machine)": A software that simulates a central process unit (Virtual Machine) to run compiled Java code. "keystore": A database used by JDK "keytool" command and KeyStore class to store your own private keys, and public key certificates you received from someone else. "keystore" supports the following features.

Java Tools

Embed Size (px)

Citation preview

Page 1: Java Tools

Chapter - 1Java Tools Terminology

Certificate: A digitally signed statement from the issuer saying that the public key of the subject has some specific value.

Certificate Chain: A series of certificates that one certificate signs the public key of the issuer of the next certificate. Usually the top certificate (the first certificate) is self-signed, where issuer signed its own public key.

JAR (Java Archive): A platform-independent file format that aggregates many files into one. Multiple Java applets and their requisite components (.class files, images and sounds) can be bundled in a JAR file and subsequently downloaded to a browser in a single HTTP transaction, greatly improving the download speed. The JAR format also supports compression, which reduces the file size, further improving the download time. In addition, the applet author can digitally sign individual entries in a JAR file to authenticate their origin. It is fully extensible.

"jar": A command line tool for managing JAR files. "jar" is distributed as part of the JDK package from Sun.

"java": The Java launcher - A command line tool to launch Java applications. "java" is distributed as part of the JDK package from Sun.

"javac": The Java compier - A command line tool to compile Java source files. "javac" is distributed as part of the JDK package from Sun.

"javap": The Java Class File Disassembler - A command line tool that reads Java bytecode class files and disassembles them.

"jdb": The Java Debugger - A command line tool to debug Java applications. "jdb" is distributed as part of the JDK package from Sun.

"JDI (Java Debug Interface)": A high level Java API providing information useful for debuggers and similar systems needing access to the running state of a (usually remote) virtual machine.

"JPDA (Java Platform Debugger Architecture)": An infrastructure that allows user to build end-user debugger applications. It includes the following three-layered APIs:

• Java Debug Interface (JDI), a high-level Java programming language interface, including support for remote debugging;

• Java Debug Wire Protocol (JDWP), which defines the format of information and requests transferred between the debugging process and the debugger front end;

• The JVM(TM) Tools Interface, JVM TI. This is a low-level native interface that defines the services a Java virtual machine provides for tools, including debugging. JVM TI is new in J2SE 5.0 and replaces JVMDI and JVMPI, both of which are deprecated and will be removed in a future release.

"JVM (Java Virtual Machine)": A software that simulates a central process unit (Virtual Machine) to run compiled Java code.

"keystore": A database used by JDK "keytool" command and KeyStore class to store your own private keys, and public key certificates you received from someone else. "keystore" supports the following features.

Page 2: Java Tools

"keytool": A command line tool introduced in JDK 1.2 to manage keys and certificates using "keystore". "keytool" replaces the same functions offered by "javakey" in JDK 1.1. "keytool" offers a number functions through the following major command options.

native2ascii: Native-to-ASCII Encoding Converter - A command line tool that reads a text file stored in a non-ASCII encoding and converts it to an ASCII text file. All non-ASCII characters will be converted into \udddd sequences, where dddd is the Unicode code value of the non-ASCII character.

ZIP: A file format is a popular data compression and archival format. A ZIP file contains one or more files that have been compressed or stored.

The format was originally designed by Phil Katz for PKZIP. However, many software utilities other than PKZIP itself are now available to create, modify or open ZIP files, notably WinZip, BOMArchiveHelper, PicoZip, Info-ZIP, WinRAR and 7-Zip. Microsoft has also included minimal ZIP support (under the name "compressed folders") in later versions of its Windows operating system.

Page 3: Java Tools

Chapter - 2Installing J2SE 1.6.0 on Windows

This chapter provides tutorial notes on installing Java SE (JDK) on your own Windows system to allow you to run sample JDBC Java programs. Topics include downloading and installing Java SE 6; compiling and executing Java programs; installing Java documentation.

Downloading and Installing J2SE 1.6.0 on Windows

Testing J2SE 1.6.0 Installation

Downloading and Installing J2SE 1.6.0 on Windows

To learn JDBC, you have to a copy of JDK (Java Development Kit) installed on your machine. The latest version of JDK is JDK 6u2 (Java(TM) SE Development Kit 6 Update 2), which is also called Java SE 6 (Java Standard Edition 6). Here is what I did to download and install JDK 6u2 on my local machine.

• Open the Java SE Download page with this URL: http://java.sun.com/javase/downloads/. • Click the download button next to "JDK 6u2". You will see a new page with a list of different

download files of JDK 6u2. • Locate the "Windows Platform - Java(TM) SE Development Kit 6 Update 2" section. • Click the hyper link of "Windows Offline Installation (build 06), Multi-language", which links

to jdk-6u2-windows-i586-p.exe with size of 65.57 MB. • Save jdk-6u2-windows-i586-p.exe to a temporary directory. • Double-click on jdk-6u2-windows-i586-p.exe to start the installation wizard. • The installation wizard will guide you to finish the installation.

To test the installation, open a command window to try the java command. If you are getting the following output, your installation was ok: C:\>\progra~1\java\jdk1.6.0_02\bin\java -versionjava version "1.6.0_02"Java(TM) SE Runtime Environment (build 1.6.0_02-b06)Java HotSpot(TM) Client VM (build 1.6.0_02-b06, mixed mode, sharing)

Testing J2SE 1.6.0 Installation

When JDK is installed on your machine, it provides two commands for you to compile and run Java programs.

• "javac class_name.java" - Compiles a Java program stored a file named with the program class name.

• "java -cp . class_name" - Runs a compiled Java program. "-cp ." specifies the current directory as the class path.

Let's try these commands with a very simple Java program. Use NotePad to enter the following Java

Page 4: Java Tools

program into a file called Hello.java: class Hello { public static void main(String[] a) { System.out.println("Hello world!"); }}

Then compile this program in a command window with the "javac" command: C:\>\progra~1\java\jdk1.6.0_02\bin\javac Hello.java

To execute the program, use the java command: C:\>\progra~1\java\jdk1.6.0_02\bin\java HelloHello world!

Congratulations, you have successfully entered, compiled and executed your first Java program.

Page 5: Java Tools

Chapter - 3Installing J2SE 1.5.0 on Windows

Downloading and Installing J2SE 1.5.0 on Windows

Here is what I did to download and install JDK 1.5.0 on my Windows system:

1. Go to http://java.sun.com/j2se/1.5.0/download.jsp.

2. Click the "Download JDK" hyper link.

3. Follow the instructions on the Web pages to download jdk-1_5_0-windows-i586.exe to a working directory on your hard disk. This file is about 45 MB.

4. Double click on the file name: jdk-1_5_0-windows-i586.exe in the working directory in the File Explorer.

5. Follow the instruction on the installation window to finish the installation. Remember to specify the target directory as: \j2sdk1.5.0.

6. Open a command window to try the java command. If you are getting the following output, you know your installation is done correctly: C:\>\j2sdk1.5.0\bin\java -version

java version "1.5.0"Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode)

Testing J2SE 1.5.0 Installation

Now let's test the JDK 1.5 installation.

1. Use NotePad to enter the following Java program: class Hello { public static void main(String[] a) { System.out.println("Hello world!"); }}

2. Save this program with the file Hello.java in a working folder C:\herong

3. Then compile this program in a command window with the javac command: C:\>cd \herongC:\herong> \j2sdk1.5.0\bin\javac Hello.java

3. Finally, execute the program using the java command: C:\herong>\j2sdk1.5.0\bin\java -cp . Hello

Hello world!

Page 6: Java Tools

Congratulations, you have successfully entered, compiled and executed your first Java program with your newly installed JDK 1.5.0.

Page 7: Java Tools

Chapter - 4'javac' - The Java Program Compiler

This chapter describes the Java compilation tool 'javac'. Topics include listing of 'javac' options, specifying class path with '-classpath', specifying source path with '-sourcpath', processing 'import' statements, generating debugging information with '-g'.

'javac' - Java Compilation Command and Options

Compiling Hello.java - My First Java Program

Option '-classpath' - Specifying Class Path

Option '-sourcepath' - Specifying Source Path

Option '-d' - Specifying Output Directory

Two Types of 'import' Statements

'import' Statements Processed by 'javac'

Option "-g" - Controlling Debugging Information

Conclusions:

• "javac" is the standard compiler in JDK. • "-sourcepath" specifies places where to search for source definitions of new types. • "-classpath" specifies places where to search for class definitions of new types. • Two types of "import" statements behave differently with "javac". • Never distribute your class files with debugging information in them.

'javac' - Java Compilation Command and Options

"javac": A command line tool that reads Java source files and compiles them into bytecode class files. "javac" is distributed as part of the Sun JDK package and represented by the \j2sdk1.5.0\bin\javac.exe program file. It has the following syntax: javac [options] [sourcefiles]

where "options" is a list of options and "sourcefiles" is a list of Java source files.

Commonly used options are:

• "-help" - Displays a short help text. • "-verbose" - Generates verbose output to standard output. • "-classpath classpath" - Specifies a list of path names where the compiler will search for

compiled type definitions. If "-classpath" is not specified, the current directory will be used as the class path.

• "-sourcepath sourcepath" - Specifies a list of path names where the compiler will search for source type definitions. If "-source" is not specified, the current directory will be used as the source path.

• "-d directory" - Specifies the directory where the compiler will store the generated class files. If

Page 8: Java Tools

"-d" is not specified, the class files will be stored in the same places as the source files. • "-g | -g:none" - Asks the compiler to generate debugging information into the class files or

generates no debugging information at all.

If you run the "javac" command without any options, you will get the quick usage information as shown below: C:\>\j2sdk1.5.0\bin\javac

Usage: javac <options> <source files>where possible options include: -g Generate all debugging info -g:none Generate no debugging info -g:{lines,vars,source} Generate only some debugging info -nowarn Generate no warnings -verbose Output messages about what the compiler is doing -deprecation Output source locations where deprecated APIs are used -classpath <path> Specify where to find user class files -cp <path> Specify where to find user class files -sourcepath <path> Specify where to find input source files -bootclasspath <path> Override location of bootstrap class files -extdirs <dirs> Override location of installed extensions -endorseddirs <dirs> Override location of endorsed standards path -d <directory> Specify where to place generated class files -encoding <encoding> Specify character encoding used by source files -source <release> Provide source compatibility with specified release -target <release> Generate class files for specific VM version -version Version information -help Print a synopsis of standard options -X Print a synopsis of nonstandard options -J<flag> Pass <flag> directly to the runtime system

Compiling Hello.java - My First Java Program

To test the compiler, I wrote my first Java program with a text editor: class Hello { public static void main(String[] a) { System.out.println("Hello world!"); }}

Then I saved this program with the file Hello.java in a working directory C:\herong

Here is what I did in a command window to compile Hello.java with the 'javac' Java compiler tool. The output of the compilation is a Java class file called Hello.class: C:\>cd \herong

C:\herong>\j2sdk1.5.0\bin\javac Hello.java

C:\herong>dir Hello.* 416 Hello.class

Page 9: Java Tools

116 Hello.java

As you can see from this tutorial, the simplest way to use the 'javac' Java compiler is to:

• Open a command line window. • Change the current directory to the directory with the Java program is stored. • Run the 'javac' Java compiler tool with the full path name \j2sdk1.5.0\bin\javac.exe. • The compilation output file is a class file, stored in the current directory.

Option '-classpath' - Specifying Class Path

The most commonly used "javac" option is "-classpath", which specifies a list of path names where the compiler will search for compiled type definitions. If "-classpath" is not specified, the current directory will be used as the class path.

When compiler encounters an unknown type in the source file, it will try to find the type definition by searching class files in the class path.

To experiment how the compiler uses "-classpath", I wrote the following simple source file, EchoerTest.java: /** * EchoerTest.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */public class EchoerTest { public static void main(String[] a) { Echoer e = new Echoer(); e.setReq("Hello world!"); System.out.println(e.getRes()); }}

When I tried to compile this source file, I got the following error: C:\herong>javac EchoerTest.java

EchoerTest.java:7: cannot resolve symbolsymbol : class Echoerlocation: class EchoerTest Echoer e = new Echoer();

As you can see, the compiler failed to find the definition for the type "Echoer".

In order to help the compiler to find the missing type definition, I wrote the following source code for the Echoer class, Echoer.java: /** * Echoer.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */public class Echoer { private String req = null; private String res = null; public void setReq(String r) { req = new String(r);

Page 10: Java Tools

char[] a = r.toCharArray(); int n = a.length; for (int i=0; i<n/2; i++) { char t = a[i]; a[i] = a[n-1-i]; a[n-i-1] = t; } res = new String(a); } public String getRes() { return res; }}

Then I compiled the Echoer.java and provided Echoer.class to the class path to compile EchoerTest.java: C:\herong>javac Echoer.java

C:\herong>javac -verbose -classpath . EchoerTest.java[parsing started EchoerTest.java][parsing completed 30ms][loading \j2sdk1.5.0\jre\lib\rt.jar(java/lang/Object.class)][loading \j2sdk1.5.0\jre\lib\rt.jar(java/lang/String.class)][checking EchoerTest][loading .\Echoer.class][loading \j2sdk1.5.0\jre\lib\rt.jar(java/lang/System.class)][loading \j2sdk1.5.0\jre\lib\rt.jar(java/io/PrintStream.class)][loading \j2sdk1.5.0\jre\lib\rt.jar(java/io/FilterOutputStream.class)][loading \j2sdk1.5.0\jre\lib\rt.jar(java/io/OutputStream.class)][wrote EchoerTest.class][total 221ms]

C:\herong>java EchoerTest!dlrow olleH

Note that:

• I used "-classpath ." to specify the current directory as the class path for the compiler to search for the class definition of "Echoer".

• The compiler loaded .\Echoer.class correctly, when Echoer definition was needed. • The compiler loaded other class definitions from the "rt.jar" from the system path.

Option '-sourcepath' - Specifying Source Path

If you use a new type, and you don't have the class definition of that type, but you have its source definition, you can use the "-sourcepath sourcepath" option to tell compiler to get that source definition.

Let's use the same source files, Echoer.java and EchoerTest.java, to test this: C:\herong>del Echoer.classC:\herong>del EchoerTest.class

C:\herong>javac -verbose -sourcepath . EchoerTest.java[parsing started EchoerTest.java][parsing completed 30ms]

Page 11: Java Tools

[loading \j2sdk1.5.0\jre\lib\rt.jar(java/lang/Object.class)][loading \j2sdk1.5.0\jre\lib\rt.jar(java/lang/String.class)][checking EchoerTest][loading .\Echoer.java][parsing started .\Echoer.java][parsing completed 0ms][loading \j2sdk1.5.0\jre\lib\rt.jar(java/lang/System.class)][loading \j2sdk1.5.0\jre\lib\rt.jar(java/io/PrintStream.class)][loading \j2sdk1.5.0\jre\lib\rt.jar(java/io/FilterOutputStream.class)][loading \j2sdk1.5.0\jre\lib\rt.jar(java/io/OutputStream.class)][wrote EchoerTest.class][checking Echoer][loading \j2sdk1.5.0\jre\lib\rt.jar(java/lang/StringBuffer.class)][wrote .\Echoer.class][total 230ms]

C:\herong>java EchoerTest!dlrow olleH

Note that:

• I used "-sourcepath ." to specify the current directory as the source path for the compiler to search for the source definition of "Echoer".

• The compiler loaded .\Echoer.java correctly, when Echoer definition was needed. • The compiler finished EchoerTest compilation first, then continued to compile Echoer.

Option '-d' - Specifying Output Directory

If you are writing a real Java application, you will organize your Java classes into packages. The Java source files must be stored in a directory with the path names match the package names. For example, if a source file, Some.java, is defined in a package name as: "com.herong.util", it must be stored in a directory named as: .\com\herong\util\Some.java.

By default, "javac" will output the class file in the same directory as the source file. But you can change this default behavior by using the "-d" option. It will make "javac" to output the class files into the specified directory.

To test this option, I wrote the following Java source file: PackagedHello.java /** * PackagedHello.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */package com.herong.util;public class PackagedHello { public static void main(String[] a) { System.out.println("Packaged: Hello world!"); }}

Test 1 - Storing PackagedHello.java in the wrong directory: C:\herong>dir PackagedHell.* 264 PackagedHello.java

Page 12: Java Tools

C:\herong>javac PackagedHello.java

C:\herong>dir PackagedHell.* 459 PackagedHello.class 264 PackagedHello.java

C:\herong>java -cp . PackagedHelloException in thread "main" java.lang.NoClassDefFoundError: PackagedHello (wrong name: com/herong/util/PackagedHello)

This proves that packaged classes can not be stored in any directory.

Test 2 - Storing PackagedHello.java in the right directory: C:\herong>mkdir .\comC:\herong>mkdir .\com\herongC:\herong>mkdir .\com\herong\util

C:\herong>copy PackagedHello.java .\com\herong\util

C:\herong>del PackagedHell.*

C:\herong>javac .\com\herong\util\PackagedHello.java

C:\herong>dir .\com\herong\util 459 PackagedHello.class 264 PackagedHello.java

C:\herong>java -cp . com.herong.util.PackagedHelloPackaged: Hello world!

As you can see, the compiler outputs the class file in the same directory as the source file by default.

Test 3 - Outputing PackagedHello.class to a new directory: C:\herong>mkdir .\clsC:\herong>javac -d .\cls .\com\herong\util\PackagedHello.java

C:\herong>dir .\cls\com\herong\util 459 PackagedHello.class

C:\herong>java -cp .\cls com.herong.util.PackagedHelloPackaged: Hello world!

This time, the compiler outputs the class file under a directory path: .\cls.

Two Types of 'import' Statements

Java offers two types of "import" statements:

1. Single Type Import: "import TypeName;" - It loads the definition of a single type immediately from the specified package.

2. On-Demand Type Import: "import PackageName.*;" - It tells JVM to search this package for any missing type.

"javac" command processes there two different types of "import" statements differently. I wrote the

Page 13: Java Tools

following 4 source files.

1. ClsA.java: /** * ClsA.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */package com.herong.util;public class ClsA { public void printInfo() { System.out.println("Class: com.herong.util.ClsA"); }}

2. ClsB.java: /** * ClsB.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */package com.herong.util;public class ClsB { public void printInfo() { System.out.println("Class: com.herong.util.ClsB"); }}

3. ImportTestA.java: /** * ImportTestA.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */import com.herong.util.*;public class ImportTestA { public static void main(String[] arg){ ClsA a = new ClsA(); a.printInfo(); ClsB b = new ClsB(); b.printInfo(); }}

4. ImportTestB.java: /** * ImportTestB.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */import com.herong.util.ClsA;import com.herong.util.ClsB;public class ImportTestB { public static void main(String[] arg){ ClsA a = new ClsA(); a.printInfo(); ClsB b = new ClsB(); b.printInfo(); }}

Page 14: Java Tools

Read the following section to see how "javac" compilation tool processing "import" statements.

'import' Statements Processed by 'javac'

After saving all 4 source files described in the previous section, I did the following: C:\herong>mkdir .\comC:\herong>mkdir .\com\herongC:\herong>mkdir .\com\herong\util

C:\herong>copy ClsA.java .\com\herong\utilC:\herong>copy ClsB.java .\com\herong\util

C:\herong>javac ImportTestA.javaImportTestA.java:8: cannot access ClsAbad class file: .\ClsA.javafile does not contain class ClsAPlease remove or make sure it appears in the correct subdirectory ofthe classpath. ClsA a = new ClsA(); ^1 error

What's wrong with ImportTestA.java, which uses the "On-demand type import" statement? The answer is obvious if we use the -verbose compiler option: C:\herong>javac -verbose ImportTestA.java[parsing started ImportTestA.java][parsing completed 30ms][loading c:\j2sdk1.4.2\jre\lib\rt.jar(java/lang/Object.class)][loading c:\j2sdk1.4.2\jre\lib\rt.jar(java/lang/String.class)][checking ImportTestA][loading .\ClsA.java][parsing started .\ClsA.java][parsing completed 0ms]ImportTestA.java:8: cannot access ClsAbad class file: .\ClsA.javafile does not contain class ClsAPlease remove or make sure it appears in the correct subdirectory ofthe classpath. ClsA a = new ClsA(); ^[total 230ms]1 error

C:\herong>javac -verbose ImportTestB.java[parsing started ImportTestB.java][parsing completed 30ms][loading .\com\herong\util\ClsA.class][loading .\com\herong\util\ClsB.class][loading c:\j2sdk1.4.2\jre\lib\rt.jar(java/lang/Object.class)][loading c:\j2sdk1.4.2\jre\lib\rt.jar(java/lang/String.class)][checking ImportTestB][wrote ImportTestB.class][total 221ms]

Page 15: Java Tools

What happened with ImportTestA.java compilation was that:

• First, the compiler reached "import com.herong.util.*;", but it did not load any type definition. • Then, the compiler reached "ClsA a = new ClsA();", it started to search for the definition of

"ClsA". • Then, the compiler found "ClsA.java" in the current directory. • Then, the compiler found out that "ClsA.java" is in the wrong directory path comparing with its

package name.

The compilation of ImportTestB.java went very smoothly:

• First, the compiler reached "import com.herong.util.ClsA;", it loaded .\com\herong\util\ClsA.class immediately. ClsA.java has already compiled by the previous test.

• Then, the compiler reached "import com.herong.util.ClsB;", it loaded .\com\herong\util\ClsB.class immediately. ClsB.java has already compiled by the previous test.

• Then, the compiler reached "ClsA a = new ClsA();", it had the definition of ClsA ready to use, no search needed.

• Then, the compiler reached "ClsB b = new ClsB();", it had the definition of ClsB ready to use, no search needed.

Of course, we know how to fix the problem. Just remove ClsA.java and ClsB.java from the current directory. "javac" will continue to search for the ClsA in the package specified in "import com.herong.util;".

This test shows us that:

• "Single type import" statements load classes immediately. • "javac" searches for definitions of new types first in the loaded classes, then in the source path,

and finally in the packages specified in the "On-demand type import" statements.

Option "-g" - Controlling Debugging Information

As we see earlier, the "-g" compiler option can be used to control how much debugging information should be generated into the class files. Here are the choices on how to use this option: Choice Option Information generated in class 1 -g:none No debug information 2 -g:lines Line number only 3 -g:lines,source Line number & source file 4 (default) Same as #3 5 -g:lines,source,vars Line number, source file & variables 6 -g Same as #5

Of course, the more debugging information you generate in a class file, the more debugging power you will get when you debug this class. However, once your source code is fully debugged, you should recompile your code with "-g:none", so that you don't distribute you class file will any debugging information.

Leaving debugging information in your class file will have the following negative effects:

• Class file will be larger - Harder to distribute. Longer time to load. • Easier for others to reverse engineer your source code.

Page 16: Java Tools

Chapter - 5'java' - The Java Program Launcher

This chapter describes the Java launch tool 'java'. Topics include listing of 'java' options, specifying class path with '-classpath', specifying an executable JAR file with '-jar', specifying non-standard options with '-X', launching Java programs without the console window.

'java' - Java Launching Command and Options

Launching Hello.java - My First Java Program

Option "-classpath" - Specifying Class Path

Option '-jar' - Specifying Executable JAR Files

Option '-X' - Specifying Non-Standard Options

'javaw' - Launching Java Programs without Console

Conclusions:

• "java" is the standard application launcher in JDK. • "-sourcepath" specifies places where to search for class definitions of new types. • "-jar" specifies a JAR file and launches the class specified in the manifest file. • "javaw" is identical to "java" except that it will not create the console window.

'java' - Java Launching Command and Options

"java": A command line tool that launches Java applications. It starts a Java virtual machine, loads the specified class, and invokes that class's main method. "java" has the following syntax: java [options] class [arguments]

where "options" is a list of options; "class" is the full name of a Java class to be launched; "arguments" is a list of arguments to be passed to the main method of the class to be launched.

Another way of launching a Java class is to use the "-jar" option: java [options] -jar file [arguments]

where "file" is a JAR file, which should contain a "Main-Class" attribute in the manifest file. The "Main-Class" attibute defines the Java class to be launched.

Commonly used options are:

• "-help" - Displays a short help text. • "-verbose" - Generates verbose output to standard output. • "-version" - Prints the version information of the launcher. • "-classpath classpath" - Specifies a list of path names where the launcher will search for

compiled type definitions. If "-classpath" is not specified, the current directory will be used as the class path.

Page 17: Java Tools

• "-Dproperty=value" - Defines a new system property, which can be accessed by the application.

If you run the "java" command without any options, you will get the quick usage information as shown below: C:\>\j2sdk1.5.0\bin\java

Usage: java [-options] class [args...] (to execute a class) or java [-options] -jar jarfile [args...] (to execute a jar file)

where options include: -client to select the "client" VM -server to select the "server" VM -hotspot is a synonym for the "client" VM [deprecated] The default VM is client.

-cp <class search path of directories and zip/jar files> -classpath <class search path of directories and zip/jar files> A ; separated list of directories, JAR archives, and ZIP archives to search for class files. -D<name>=<value> set a system property -verbose[:class|gc|jni] enable verbose output -version print product version and exit -version:<value> require the specified version to run -showversion print product version and continue -jre-restrict-search | -jre-no-restrict-search include/exclude user private JREs in the version search -? -help print this help message -X print help on non-standard options -ea[:<packagename>...|:<classname>] -enableassertions[:<packagename>...|:<classname>] enable assertions -da[:<packagename>...|:<classname>] -disableassertions[:<packagename>...|:<classname>] disable assertions -esa | -enablesystemassertions enable system assertions -dsa | -disablesystemassertions disable system assertions -agentlib:<libname>[=<options>] load native agent library <libname>, e.g. -agentlib:hprof see also, -agentlib:jdwp=help and -agentlib:hprof=help -agentpath:<pathname>[=<options>] load native agent library by full pathname -javaagent:<jarpath>[=<options>] load Java programming language agent, see java.lang.instrument

Launching Hello.java - My First Java Program

To test the Java launcher, 'java', I wrote the following Java file, Hello.java:

Page 18: Java Tools

class Hello { public static void main(String[] a) { System.out.println("Hello world!"); }}

Here is what I did in a command window to compile Hello.java into Hello.class: C:\herong>javac Hello.java

C:\herong>dir Hello.* 416 Hello.class 116 Hello.java

C:\herong>java HelloHello world!

As you can see, launching a simple Java application is easy - Run the 'java' command without any options.

Option "-classpath" - Specifying Class Path

The most commonly used "java" option is "-classpath", which specifies a list of path names where the launcher will search for compiled type definitions. If "-classpath" is not specified, the current directory will be used as the class path.

To experiment how the compiler uses "-classpath", I wrote the following simple source file, Echoer.java: /** * Echoer.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */public class Echoer { private String req = null; private String res = null; public void setReq(String r) { req = new String(r); char[] a = r.toCharArray(); int n = a.length; for (int i=0; i<n/2; i++) { char t = a[i]; a[i] = a[n-1-i]; a[n-i-1] = t; } res = new String(a); } public String getRes() { return res; }}

I also wrote the following testing class, EchoerTest.java: /** * EchoerTest.java

Page 19: Java Tools

* Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */public class EchoerTest { public static void main(String[] a) { Echoer e = new Echoer(); e.setReq("Hello world!"); System.out.println(e.getRes()); }}

Then I stored them in two different directories, and tried to launch EchoerTest: C:\herong>mkdir echoC:\herong>copy Echoer.java echo

C:\herong>mkdir testC:\herong>copy EchoerTest.java test

C:\herong>cd test

C:\herong>javac -classpath ..\echo EchoerTest.java

>java EchoerTestException in thread "main" java.lang.NoClassDefFoundError: Echoer at EchoerTest.main(EchoerTest.java:7)

C:\herong>java -classpath ..\echo EchoerTestException in thread "main" java.lang.NoClassDefFoundError: EchoerTest

C:\herong>java -classpath .;..\echo EchoerTest!dlrow olleH

Note that:

• The first time I tried to launch "EchoerTest" without "-classpath", "java" failed to find "Echoer" class, because "java" uses the current directory as the default class path.

• The second time I tried to launch "EchoerTest" with "-classpath ..\echo", "java" failed to find "EchoerTest" class, because the specified class path didn't include the current directory.

• The third time I tried to launch "EchoerTest" with "-classpath .;..\echo", "java" was able to find both "EchoerTest" and "Echoer".

Option '-jar' - Specifying Executable JAR Files

In order to use the "-jar" option, we need to create a JAR file with a "Main-Class" attribute in the manifest file.

Here is what I did to create a JAR file, and launch it with the "-jar" option.

First I created a manifest file, hello.fs: Main-Class: Hello

Then I created an executable JAR file, hello.jar, with Hello.class and hello.fs:

Page 20: Java Tools

C:\herong>javac Hello.java

C:\herong>jar -cvmf hello.fs hello.jar Hello.classadded manifestadding: Hello.class(in = 416) (out= 285)(deflated 31%)

Finally, I launched the Hello.class program included in the executable JAR file: C:\herong>java -jar hello.jarHello world!

Option '-X' - Specifying Non-Standard Options

"java" can also take "non-standard" options by using the "-X" option.

Two of the "non-standard" options are very useful to control the memory size of the JVM to be launched. -Xmsn -Xmxn

where "ms" specifies the initial size of the JVM, "mx" specifies the maximum size of the JVM, and "n" specifies the memory size in bytes, kilo bytes or mega bytes. For example: -Xms32M and -Xmx64M.

Here is a program to show you how to use these options: /** * ShowMemory.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */class ShowMemory { public static void main(String[] a) { Runtime rt = Runtime.getRuntime(); System.out.println(" Free memory: " + rt.freeMemory()); System.out.println("Total memory: " + rt.totalMemory()); while (true); }}

I launched the program with different options: C:\herong>javac ShowMemory.java

C:\herong>java ShowMemory Free memory: 1896232Total memory: 2031616

C:\herong>java -Xms32M -Xmx128M ShowMemory Free memory: 33222440Total memory: 33357824

C:\herong>java -Xms64M -Xmx128M ShowMemory Free memory: 66514728Total memory: 66650112

Page 21: Java Tools

'javaw' - Launching Java Programs without Console

If you launch a Java application with "java" in a command window, JVM will use that command window as the console. If you launch a Java application with "java" in a different way, "java" will create new command window and use it as the console.

If you don't want console, you can user "javaw" launch your application. "javaw" works exactly like "java" except that it will not create any console.

Here is what I did to test the "javaw" tool.

1. Compile ShowMemory.java and copy ShowMemory.class to c:\herong.

2. Go to Start > Run, type "java -classpath c:\herong ShowMemory", and click OK.

3. You should see a command window showing up displaying the program output. "java" tool created this window as the console.

4. Go to Start > Run, type "javaw -classpath c:\herong ShowMemory", and click OK.

5. You should see no command window showing up. But what happens to my program? Is it still running?

6. Go to Start > Run, type "taskmgr", and click OK. The Windows Task Manager windows shows up.

7. Go to "Process" tab, you should see two Java processes: "java" and "javaw". This answers my previous question. "javaw" is still running ShowMemory without any console as expected.

Through this tutorial, we should remember that when you use "javaw" to launch an application, no console window will be created and data sent to the standard output stream will not be displayed. So "javaw" is good tool for applications that do not need the console window, like GUI applications and server applications.

Page 22: Java Tools

Chapter - 6

'jdb' - The Java Debugger

This chapter provides tutorial notes on the Java debugger 'jdb'. Topics include starting 'jdb' to debug an application, running 'jdb' separately from the application, debugging remote application, debugging multi-thread application, listing and switching execution threads.

'jdb' - Java Debugger Command and Options

Starting a Debugging Session with 'jdb'

Debugging Applications with Separate 'jdb' Sessions

Debugging Java Applications Remotely

Listing Debugging Commands with 'help' Command

PrimeNumberSeeker.java - Multi-Thread Sample Program

Starting Debugging Session on a Multi-Thread Application

Stepping through Statements of the Child Thread

Checking Variable Values in a Debugging Session

Debugging the Main Thread of a Multi-Thread Application

Switching Execution Threads in a Debugging Session

Suspending Main Thread to Debug Child Thread

Conclusions:

• "jdb" is a nice debugging tool. But it only offers a command line interface, not so easy to use. It is much more efficient to use graphical interface debugger.

• JPDA is well designed, allowing us to debug Java applications remotely. • Debugging multi-thread application is tricky. The following "jdb" notes may help you. • Whenever one thread reaches a break point, all other threads are stopped also. • The command prompt tells what is the current thread. • "where all" tells where the execution are currently in all threads. • "threads" lists all the threads with thread indexes as Hex numbers.

'jdb' - Java Debugger Command and Options

"jdb": A command line tool that allows you to debug a Java application interactively with in a command line mode. "javac" is distributed as part of the Sun JDK package. It has the following syntax: jdb [options] main_class_namejdb [options] -attach <address>

where "options" is a list of options, "main_class_name" is a the name of the main class of a Java application, and "address" is the debugging connection address of a running Java application.

Page 23: Java Tools

As you can see from the syntax, there are two ways of running "jdb":

1. Running "jdb" to launch a Java application and start a debug session on that application.

2. Running "jdb" to connect to a separately launched Java application and start a debug session on that application.

Commonly used options are:

• "-help" - Displays a short help text. • "-verbose" - Generates verbose output to standard output. • "-classpath classpath" - Specifies a list of path names where the launcher will search for

compiled type definitions. • "-Dproperty=value" - Defines a new system property, which can be accessed by the application. • "-launch" - Launches the debugged application immediately upon startup of jdb. This option

removes the need for using the run command. The target application is launched and then stopped just before the initial application class is loaded. At that point you can set any necessary breakpoints and use the cont to continue execution.

Note that in order to use all debugging commands, the target application must be compiled with "-g" option, which will generate all debugging information, including source file, line number, and local variables, into the class file.

Starting a Debugging Session with 'jdb'

To test the debugger, I wrote the following simple Java application, Hello.java: class Hello { public static void main(String[] a) { System.out.println("Hello world!"); }}

Here is what I did in a command window to run "jdb" to launch and debug Hello.java: C:\herong>javac Hello.java

C:\herong>jdb HelloInitializing jdb ...

> stop in Hello.mainDeferring breakpoint Hello.main.It will be set after the class is loaded.

> runrun HelloSet uncaught java.lang.ThrowableSet deferred uncaught java.lang.Throwable>VM Started: Set deferred breakpoint Hello.main

Breakpoint hit: "thread=main", Hello.main(), line=3 bci=03 System.out.println("Hello world!");

main[1] nextHello world!

Page 24: Java Tools

>Step completed: "thread=main", Hello.main(), line=4 bci=84 }

main[1] cont>The application exited

Notice that:

• Once started, "jdb" offers you command prompt to allow you to run debugging commands interactively.

• Without the "-launch" option, "jdb" will not start the main() method of the specified class. • "stop in" command sets a breakpoint at the beginning of the specified method. See the next

section for other commonly used debugging commands. • "run" command starts a new JVM process with run your application in debug mode. • "jdb" and the JVM of your application are different processes. If you use Windows Task

Manager, you should see two processes named as "jdb" and "java". • "next" command executes only the current statement of the debugged application. • "cont" command resumes the execution to the end or the next breakpoint.

If you want to launch the target application immediately, you can use the "-launch" option: C:\herong>jdb -launch HelloSet uncaught java.lang.ThrowableSet deferred uncaught java.lang.ThrowableInitializing jdb ...>VM Started: No frames on the current call stack

main[1] cont> Hello world!

The application has been disconnected

As we expected, "jdb -launch" command launches the target application immediately, and stops at the beginning of the main() method.

Debugging Applications with Separate 'jdb' Sessions

If you ask "Can I launch the debugger ('jdb') and the target application separately?", the answer is "Yes, you can.". In JDK 1.5, both "jdb" and "java" have been enhanced to use the latest JPDA (Java Platform Debugger Architecture) technology to give you the following options: Debugger TargetOption jdb java

1 Shared memory client Shared memory server 2 Shared memory server Shared memory client 3 Socket client Socket server 4 Socket server Socket client

The shared memory options requires that the debugger and the target application to be on the same machine. Of course, the socket options allow you to run them remotely.

Page 25: Java Tools

Let's try option #1 first. Open a command window on a windows system and run: C:\herong>java -agentlib:jdwp=transport=dt_shmem,address=MyHello,server=y, suspend=y Hello

Listening for transport dt_shmem at address: MyHello

The target application is launched in "shared memory server" mode. Its execution is suspended. Now open another command window and run: C:\herong>jdb -attach MyHelloSet uncaught java.lang.ThrowableSet deferred uncaught java.lang.ThrowableInitializing jdb ...>VM Started: No frames on the current call stack

main[1] stop in Hello.mainDeferring breakpoint Hello.main.It will be set after the class is loaded.

main[1] cont> Set deferred breakpoint Hello.main

Breakpoint hit: "thread=main", Hello.main(), line=3 bci=03 System.out.println("Hello world!");

main[1] list1 public class Hello {2 public static void main(String[] a) {3 => System.out.println("Hello world!");4 }5 }

main[1] cont>The application exited

As you can see, the debugger successfully connected to the target application. I used "next" command to let the target application to execute the current statement.

Debugging Java Applications Remotely

As we can see from the previous section, we can run a Java application and the 'jdb' debugger separately in shared memory mode. But this requires that the Java application and the 'jdb' debugger must be running on the same machine. If you have a large application that you need to run a big server machine, you can debug that application by running the 'jdb' debugger on your own desktop machine using the socket debugging communication mode as presented in the previous section.

Let's try it now. Open a command window on a windows system and run: C:\herong>java -agentlib:jdwp=transport=dt_socket, address=localhost:8888,server=y,suspend=y Hello

Listening for transport dt_socket at address: 8888

Page 26: Java Tools

The target application is launched in "socket server" mode. Its execution is suspended. Now open another command window and run: C:\herong>jdb -connect com.sun.jdi.SocketAttach:hostname=localhost, port=8888

Set uncaught java.lang.ThrowableSet deferred uncaught java.lang.ThrowableInitializing jdb ...>VM Started: No frames on the current call stack

main[1] stop in Hello.mainDeferring breakpoint Hello.main.It will be set after the class is loaded.

main[1] cont> Set deferred breakpoint Hello.main

Breakpoint hit: "thread=main", Hello.main(), line=3 bci=03 System.out.println("Hello world!");

main[1] quite

Cool. I know how to run "jdb" to debug an application running on a remote machine now!

However, the command suggested in the JPDA documentation did not work: C:\herong>jdb -attach localhost:8888java.io.IOException: shmemBase_attach failed: The system cannot find the file specified at com.sun.tools.jdi.SharedMemoryTransportService.attach0(... ...

My guess is that the Windows version of "jdb" assumes "shared memory" as the default transport mode.

Listing Debugging Commands with 'help' Command

Ok, I think we did enough excises about launching the debugger and connecting to the target application. Let's now move on to look at some debugging commands.

Here is list of commonly used debugging commands. I got this list by using "help" at debugging prompt. C:\herong>jdb> run

...run [class [args]] -- start execution of an application

threads [threadgroup] -- list threadsthread <thread id> -- set default threadsuspend [thread id(s)] -- suspend threads (default: all)resume [thread id(s)] -- resume threads (default: all)where [<thread id> | all] -- dump a thread's stackup [n frames] -- move up a thread's stackdown [n frames] -- move down a thread's stack

Page 27: Java Tools

kill <thread id> <expr> -- kill a thread with the given exceptioninterrupt <thread id> -- interrupt a thread

print <expr> -- print value of expressiondump <expr> -- print all object informationeval <expr> -- evaluate expression (same as print)set <lvalue> = <expr> -- assign new value to a variablelocals -- print all local variables

classes -- list currently known classesclass <class id> -- show details of named classmethods <class id> -- list a class's methodsfields <class id> -- list a class's fields

threadgroups -- list threadgroupsthreadgroup <name> -- set current threadgroup

stop in <class id>.<method>[(argument_type,...)] -- set a breakpoint in a methodstop at <class id>:<line> -- set a breakpoint at a lineclear <class id>.<method>[(argument_type,...)] -- clear a breakpoint in a methodclear <class id>:<line> -- clear a breakpoint at a lineclear -- list breakpointscatch [uncaught|caught|all] <class id>|<class pattern> -- break when specified exception occursignore [uncaught|caught|all] <class id>|<class pattern> -- cancel 'catch'

watch [access|all] <class id>.<field name> -- watch access/modifications to a fieldunwatch [access|all] <class id>.<field name> -- discontinue watchingtrace methods [thread] -- trace method entry and exituntrace methods [thread] -- stop tracing method entry and exitstep -- execute current linestep up -- execute until the current method returnsstepi -- execute current instructionnext -- step one line (step OVER calls)cont -- continue execution from breakpoint

list [line number|method] -- print source codeuse (or sourcepath) [source file path] -- display or change the source pathclasspath -- print classpath info from target VM

monitor <command> -- execute specified command at stop timemonitor -- list monitorsunmonitor <monitor#> -- delete a monitorread <filename> -- read and execute a command file

lock <expr> -- print lock info for an objectthreadlocks [thread id] -- print lock info for a thread

disablegc <expr> -- prevent garbage collection of an objectenablegc <expr> -- permit garbage collection of an object

!! -- repeat last command<n> <command> -- repeat command n times

Page 28: Java Tools

help (or ?) -- list commandsversion -- print version informationexit (or quit) -- exit debugger

PrimeNumberSeeker.java - Multi-Thread Sample Program

To help me practice debugging commands, I wrote the following simple multi-thread application, PrimeNumberSeeker.java: 1 /** 2 * PrimeNumberSeeker.java 3 * Copyright (c) 2003 by Dr. Herong Yang, www.herongyang.com 4 */ 5 public class PrimeNumberSeeker extends Thread { 6 private static final int ceiling = 100; 7 private static final int interval = 1000; 8 private static final int delay = 100; 9 public int count = 0;10 public int current = 2;11 public int[] primes = null;12 public static void main(String[] a) {13 System.out.println("Period, Current int, # primes");14 PrimeNumberSeeker t = new PrimeNumberSeeker();15 t.start();16 int i = 0;17 while (true) {18 i++;19 System.out.println( i+", "+t.current+", "+t.count);20 try {21 sleep(interval);22 } catch (InterruptedException e) {23 System.out.println("Monitor interrupted.");24 }25 }26 }27 public void run() {28 primes = new int[ceiling];29 while (count < ceiling) {30 current++;31 int j = 2;32 boolean isPrime = true;33 while (j<current/2 && isPrime) {34 isPrime = current % j > 0;35 j++;36 }37 if (isPrime) {38 count++;39 primes[count-1] = current;40 }41 try {42 sleep(delay);43 } catch (InterruptedException e) {44 System.out.println("Runner interrupted.");45 }46 }47 }48 }

Page 29: Java Tools

Note that:

• This application tries to use a sub-thread to calculate prime numbers. • The main thread is monitoring how the sub-thread is doing. • A delay mechanism is used to slow the calculation. • The application has an infinite loop. So you have to terminate it by "Ctrl-C".

Here is how I compiled the application and executed without debugging: C:\herong>javac -g PrimeNumberSeeker.java

C:\herong>java PrimeNumberSeekerPeriod, Current int, # primes1, 2, 02, 12, 53, 22, 84, 32, 115, 42, 136, 52, 157, 62, 188, 72, 209, 82, 2210, 92, 2411, 102, 2612, 112, 2913, 122, 30...53, 521, 9854, 531, 9955, 541, 10056, 541, 10057, 541, 100...

The output seems to be fine. But I want to use "jdb" to exam the calculation and to practice the debugging commands. I will show my debugging session in multiple parts with my comments in sections below.

Starting Debugging Session on a Multi-Thread Application

1. Setting up breakpoints and getting the debugging session going: C:\herong>jdb PrimeNumberSeeker

Initializing jdb ...> stop in PrimeNumberSeeker.mainDeferring breakpoint PrimeNumberSeeker.main.It will be set after the class is loaded.

> runrun PrimeNumberSeekerSet uncaught java.lang.ThrowableSet deferred uncaught java.lang.Throwable>VM Started: Set deferred breakpoint PrimeNumberSeeker.main

Page 30: Java Tools

Breakpoint hit: "thread=main", PrimeNumberSeeker.main(), line=13 13 System.out.println("Period, Current int, # primes");

main[1] stop in PrimeNumberSeeker.runSet breakpoint PrimeNumberSeeker.run

main[1] contPeriod, Current int, # primes1, 2, 0>Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=2828 primes = new int[ceiling];

Thread-0[1] threadsGroup system: (java.lang.ref.Reference$ReferenceHandler)0xe2 Reference Handler (java.lang.ref.Finalizer$FinalizerThread)0xe1 Finalizer (java.lang.Thread)0xe0 Signal DispatcherGroup main: (java.lang.Thread)0x1 main running (PrimeNumberSeeker)0x118 Thread-0 running (at breakpoint)

Ok. What I have done so far:

• Started the debugging session with the first breakpoint at the beginning of the main() method, which cause the execution to stop at line 13.

• Then I created the second breakpoint at the beginning of the run() method in order to catch the sub thread.

• Then I issued the "cont" command. My application continued with the sub thread created stopped at the breakpoint at line 28. The main thread also stopped.

• Noticed that the debugger prompt is changed from "main[1]" to "Thread-0[1]". This is to inform you that you are currently in the sub thread, no longer in the main thread.

• Then I used the "threads" command to list all threads. I saw two thread groups: "system" and "main". Of course, I am not interested in the "system" group at this point. The "main" shows two threads: "main" (my monitoring thread) and "Thread-0" (my sub thread working on the calculation).

• Thread "Thread-0" status shows "running (at breakpoint)". But the word "running" is referring to the thread execution mode, not the current execution status.

• Notice that tread "main" is also stopped at this moment. As a general rule, if one thread is stopped, all other threads are stopped also.

Stepping through Statements of the Child Thread

2. Stepping through statements in the sub thread: Thread-0[1] where allSignal Dispatcher:Finalizer: [1] java.lang.Object.wait (native method) [2] java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:111) [3] java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:127) [4] java.lang.ref.Finalizer$FinalizerThread.run (Finalizer.java:...Reference Handler: [1] java.lang.Object.wait (native method) [2] java.lang.Object.wait (Object.java:429) [3] java.lang.ref.Reference$ReferenceHandler.run (Reference.java...

Page 31: Java Tools

main: [1] java.lang.Thread.sleep (native method) [2] PrimeNumberSeeker.main (PrimeNumberSeeker.java:21)Thread-0: [1] PrimeNumberSeeker.run (PrimeNumberSeeker.java:28)

Thread-0[1] next2, 2, 0>Step completed: "thread=Thread-0", PrimeNumberSeeker.run(), line=2929 while (count < ceiling) {

Thread-0[1] where all...main: [1] java.lang.Thread.sleep (native method) [2] PrimeNumberSeeker.main (PrimeNumberSeeker.java:21)Thread-0: [1] PrimeNumberSeeker.run (PrimeNumberSeeker.java:29)

Thread-0[1] next3, 2, 0>30 current++;

Thread-0[1] next4, 3, 0>31 int j = 2;

Thread-0[1] next> 5, 3, 032 boolean isPrime = true;

Thread-0[1] next6, 3, 0>33 while (j<current/2 && isPrime) {

Thread-0[1] list29 while (count < ceiling) {30 current++;31 int j = 2;32 boolean isPrime = true;33 => while (j<current/2 && isPrime) {34 isPrime = current % j > 0;35 j++;36 }37 if (isPrime) {38 count++;Thread-0[1] print current current = 3

What I have done here:

• I used "where all" to display the current location of all threads. • Then I used "next" to execute one statement in the current thread, the sub thread, going from

line 28 to line 29.

Page 32: Java Tools

• The next "where all" command showed me that the main thread went through an entire iteration of the "while" loop. The main thread stopped again at line 21.

• Then I used a couple of "next" command in the sub thread to bring the execution to line 33. At the same time, the main thread went through a couple of iterations, printed some output messages.

• Then I used "print" to check the current value of variable "current". Value 3 is correct.

Checking Variable Values in a Debugging Session

3. Checking local variables: Thread-0[1] next7, 3, 0>37 if (isPrime) {

Thread-0[1] print isPrime isPrime = true

Thread-0[1] next8, 3, 0>38 count++;

Thread-0[1] next9, 3, 0>39 primes[count-1] = current;

Thread-0[1] print count count = 1

Thread-0[1] next> 10, 3, 142 sleep(delay);

Thread-0[1] list38 count++;39 primes[count-1] = current;40 }41 try {42 => sleep(delay);43 } catch (InterruptedException e) {44 System.out.println("Runner interrupted.");45 }46 }47 }

Thread-0[1] print primes[0] primes[0] = 3

What I have done here:

• I used "next" again. The sub thread jumped over the calculation loop between line 33 and 36. This is correct, since "current" has "3", a prime number, no need to do any calculation.

• Then I used "next" and "print" several times. I saw prime number 3 was correctly recorded in

Page 33: Java Tools

the "primes" array.

Debugging the Main Thread of a Multi-Thread Application

4. Going back to the main thread: Thread-0[1] stop at PrimeNumberSeeker:19Set breakpoint PrimeNumberSeeker:19Thread-0[1] cont>Breakpoint hit: "thread=main", PrimeNumberSeeker.main(), line=19 bci=2519 System.out.println( i+", "+t.current+", "+t.count);

main[1] where allmain: [1] PrimeNumberSeeker.main (PrimeNumberSeeker.java:19)Thread-0: [1] java.lang.Thread.sleep (native method) [2] PrimeNumberSeeker.run (PrimeNumberSeeker.java:42)

main[1] print i i = 11

main[1] print t.current t.current = 3

main[1] print t.count t.count = 1

What I have done here:

• I created another breakpoint in the main thread at line 19. • Then I allowed both threads to run naturally to the next breakpoint, line 19. The command

prompt is changed back to "main[1]". • Then I used "where all" to check where the execution are stopped in all threads. It is interesting

to see that the sub thread stopped inside the sleep() method. • Then I checked some local variables, "i", "t.current", and "t.count". Their values were all

correct.

Switching Execution Threads in a Debugging Session

5. Switching threads: main[1] cont>Breakpoint hit: "thread=main", PrimeNumberSeeker.main(), line=19 bci=2519 System.out.println( i+", "+t.current+", "+t.count);

main[1] print t.current t.current = 14

main[1] print t.count t.count = 6

main[1] where all...

Page 34: Java Tools

main: [1] PrimeNumberSeeker.main (PrimeNumberSeeker.java:19)Thread-0: [1] java.lang.Thread.sleep (native method) [2] PrimeNumberSeeker.run (PrimeNumberSeeker.java:42)

main[1] threads...Group main: (java.lang.Thread)0x1 main running (PrimeNumberSeeker)0x118 Thread-0 running (at breakpoint)

main[1] thread 280

Thread-0[1] listCurrent method is native

Thread-0[1] step out11, 22, 8>Step completed: "thread=Thread-0", PrimeNumberSeeker.run(), line=4545 }

Thread-0[1] list41 try {42 sleep(delay);43 } catch (InterruptedException e) {44 System.out.println("Runner interrupted.");45 => }46 }47 }48 }

Thread-0[1] print count count = 8

What I have done here:

• I let the main thread executed a full period stopping at line 19 again. Of course, the sub thread execute some number of statements and stopped inside the sleep() native method.

• Then I listed all threads and want to find a way to switch the command prompt to the sub thread to check local variable there. The manual says to use "thread n", where n is the thread index to change the current thread. But where can I to get the thread index? I tried to search the Web and did not get any clear answer.

• However I got the answer from the output of the threads output. The thread index was listed as a hex number next to the class name. For example, "(PrimeNumberSeeker)0x118" means thread 0x118 = 280.

• So I used "thread 280" to switch to the sub thread as the current thread. Notice that the command prompt changed.

• The first "list" command did not work, because the sub thread was stopped inside the "sleep()" method. The "step out" command continued the execution just enough to finish "sleep()" and back to the caller, run().

Suspending Main Thread to Debug Child Thread

6. Suspending the main thread and keeping only the child thread running:

Page 35: Java Tools

Thread-0[1] stop at PrimeNumberSeeker:39Set breakpoint PrimeNumberSeeker:39

Thread-0[1] cont>Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=3939 primes[count-1] = current;

Thread-0[1] cont>Breakpoint hit: "thread=main", PrimeNumberSeeker.main(), line=1919 System.out.println( i+", "+t.current+", "+t.count);

main[1] cont> 12, 23, 9

Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=3939 primes[count-1] = current;

Thread-0[1] cont>Breakpoint hit: "thread=main", PrimeNumberSeeker.main(), line=1919 System.out.println( i+", "+t.current+", "+t.count);

main[1] suspend 1

main[1] cont>Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=3939 primes[count-1] = current;

Thread-0[1] cont>Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=3939 primes[count-1] = current;

Thread-0[1] cont>Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=3939 primes[count-1] = current;

Thread-0[1] print current current = 41

Thread-0[1] print count count = 13

What I have done here:

• After check different areas of the code, I wanted to only the break the execution when a new prime number is found. So I created a breakpoint at line 39.

• Then I used "cont" to let the execution to continue. But two threads always executed at the same time, and stopped at the same time whenever one thread reached a breakpoint.

• So I used "suspend 1" to suspend the main thread. This is a cool command, allowing me to concentrate on a single thread. Of course, you can use "resume 1" to release the suspension.

I think I have done enough debugging practice and want to stop here now. However, my program does have a calculation error. I want to leave it to you to find out.

Page 36: Java Tools

Chapter - 7

'jconsole' - Java Monitoring and Management Console

This chapter provides tutorial notes on the Java monitoring and management console, jconsole. Topics include description of JMX technology, list of 'jconsole' command options, turning on JMX agent for local and remote connection, running 'jconsole' to monitor local and remote Java applications.

JMX Technology and 'jconsole' Tool

'jconsole' Command Options and Connection Window

'com.sun.management.jmxremote' - JMX Agent for Local Connection

'jconsole' - Connecting to a Local JMX Agent

'com.sun.management.jmxremote.port' - JMX Agent for Remote Connection

'jconsole' - Connecting to a Remote JMX Agent

Conclusions:

• jconsole is a GUI tool that allows you to monitor a local or remote JVM process using the JMX (Java Management Extension) technology.

• JVM processes must be launched with the default JMX properties turned on in order to be connected by jconsole.

• jconsole displays monitoring diagrams for heap memory usage, counts on loaded classes, counts on threads, and CPU usages.

JMX Technology and 'jconsole' Tool

"JMX (Java Management Extensions)": A Java standard API for management and monitoring of resources such as applications, devices, services, and the Java virtual machine. The JMX technology was developed through the Java Community Process (JCP) as Java Specification Request (JSR) 3, Java Management Extensions, and JSR 160, JMX Remote API.

JMX has been implemented into JDK 5 now. You can set out-of-the-box JMX monitoring and management properties when you start the JVM to run your Java application. This allows you to use local or remote JMX connectors to monitor your application.

JDK 5 offers a graphical user interface called "jconsole" that uses the JMX technology to monitor your Java application locally or remotely. The picture below shows you how "jconsole" works with your Java application:

Page 37: Java Tools

'jconsole' Command Options and Connection Window

"jconsole": A graphical user interface tool that enables you to monitor and manage Java applications and virtual machines on a local or remote machine using the JMX technology.

The "jconsole" tool supports several command options, which can be obtained by the "-help" option: C:\Progra~1\java\jdk1.6.0_02\bin\jconsole -help

Usage: jconsole [ -interval=n ] [ -notile ] [ -pluginpath <path> ] [ -version ] [ connection ... ]

-interval Set the update interval to n seconds (default is 4 seconds) -notile Do not tile windows initially (for two or more connections) -pluginpath Specify the path that jconsole uses to look up the plugins -version Print program version

connection = pid || host:port || JMX URL (service:jmx:<protocol>://...) pid The process id of a target process host A remote host name or IP address port The port number for the remote connection

-J Specify the input arguments to the Java virtual machine on which jconsole is running

If you run the "jconsole" command without any option in JDK 1.6, you will get the connection window as shown below:

Page 38: Java Tools

This connection window allows you to specify the connection information from UI instead of the command line.

'com.sun.management.jmxremote' - JMX Agent for Local Connection

Since JDK 1.5, JMX has been included the Sun JVM. You can turn on the out-of-the-box JMX agent when you launch the JVM to run your application. This enables "jconsole" to connect to the JMX agent to monitor you Java application local or remotely.

In order to run your Java application and allow "jconsole" to monitor it on the local machine, you need to turn the "com.sun.management.jmxremote" system property with the "-D" option on the "java" command.

To this out, I modified the my PrimeNumberSeeker.java program with a higher ceiling value of 1000000 to let the loop running much longer: /** * PrimeNumberSeeker.java * Copyright (c) 2008 by Dr. Herong Yang, http://www.herongyang.com/ */public class PrimeNumberSeeker extends Thread { private static final int ceiling = 1000000; private static final int interval = 1000; private static final int delay = 100; public int count = 0; public int current = 2; public int[] primes = null; public static void main(String[] a) { System.out.println("Period, Current int, # primes"); PrimeNumberSeeker t = new PrimeNumberSeeker(); t.start(); int i = 0; while (true) { i++; System.out.println( i+", "+t.current+", "+t.count); try {

Page 39: Java Tools

sleep(interval); } catch (InterruptedException e) { System.out.println("Monitor interrupted."); } } } public void run() { primes = new int[ceiling]; while (count < ceiling) { current++; int j = 2; boolean isPrime = true; while (j<current/2 && isPrime) { isPrime = current % j > 0; j++; } if (isPrime) { count++; primes[count-1] = current; } try { sleep(delay); } catch (InterruptedException e) { System.out.println("Runner interrupted."); } } }}

To run this program with the out-of-the-box JMX agent turned on, I used the following commands: C:\Progra~1\java\jdk1.6.0_02\bin\javac PrimeNumberSeeker.java

C:\Progra~1\java\jdk1.6.0_02\bin\java -Dcom.sun.management.jmxremote PrimeNumberSeeker

Period, Current int, # primes1, 2, 02, 10, 4...

Now my application PrimeNumberSeeker.java is running with the JMX agent turned on for local connection. See the next section on how to run "jconsole" to monitor this application.

'jconsole' - Connecting to a Local JMX Agent

If you follow the tutorial presented in the previous section, the PrimeNumberSeeker.java is running in a JVM with the default JMX agent turned on.

Now we can run "jconsole" to connect to this JVM to monitor how my PrimeNumberSeeker.java is running in two ways:

1. Find out the PID (Process ID) of this JVM and use the "jconsole <pid>" command to start "jconsole" and connect to this JVM on the local machine.

2. Use the "jconsole" command to start "jconsole". It will search for any JVM process that has the local

Page 40: Java Tools

JMX agent turned on. You can make the connection by clicking the search result list.

Obviously, the second way is better, because I don't have figure out the PID of my running JVM process. Here what I did to run "jconsole" and connect it to the JVM that runs PrimeNumberSeeker.java:

1. Run "C:\Progra~1\java\jdk1.6.0_02\bin\jconole". The connection window shows up with 2 JVM listed in the local processes section: Name PID

sun.tools.jconsole.JConsole 2204PrimeNumberSeeker 736

2. Double click the name "PrimeNumberSeeker", the Java Monitoring & Management Console window shows with the Overview tab opened as shown in the picture below:

Cool. "jconsole" automatically collects some basic statistics like: heap memory usage, number of threads, number of classes, and CPU usage.

'com.sun.management.jmxremote.port' - JMX Agent for Remote Connection

If you want to run 'jconsole' on a remote machine to monitor a Java application, you need to launch the JVM with the default JMX agent turned on using this system property: "com.sun.management.jmxremote.port=<portNum>"

Here is what I did to run my PrimeNumberSeeker.java with the default JMX agent for remote monitoring connections:

Page 41: Java Tools

1. To run this program with the out-of-the-box JMX agent turned on, I used the following commands: C:\Progra~1\java\jdk1.6.0_02\bin\java -Dcom.sun.management.jmxremote.port=6789 PrimeNumberSeeker

Error: Password file not found: C:\Program Files\java\jdk1.6.0_02\jre \lib\management\jmxremote.password

2. I got this error because the remote JMX agent requires a password file to only give permissions to authorized remote connections. For testing purpose, I used this system property: "com.sun.management.jmxremote.authenticate=false" to turn off the authentication function: C:\Progra~1\java\jdk1.6.0_02\bin\java -Dcom.sun.management.jmxremote.port=6789 -Dcom.sun.management.jmxremote.authenticate=false PrimeNumberSeeker

Period, Current int, # primes1, 2, 02, 10, 4...

3. I tried to run "jconsole localhost:6789" to connect to this JMX agent remotely. But the connection failed with this error dialog box:

4. The connection failed because the remote JMX agent also requires a SSL client certificate. For testing purpose, I used this system property: "com.sun.management.jmxremote.ssl=false" to turn off the SSL function: C:\Progra~1\java\jdk1.6.0_02\bin\java -Dcom.sun.management.jmxremote.port=6789 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false PrimeNumberSeeker

Period, Current int, # primes1, 2, 02, 10, 4...

Now I am ready run "jconsole" to connect to this JMX agent remotely. See the next section for more tutorial examples.

'jconsole' - Connecting to a Remote JMX Agent

If you follow the tutorial presented in the previous section, the PrimeNumberSeeker.java is running in a JVM with the remote JMX agent turned on waiting for remote connections at the port: 6789.

Now we can run "jconsole localhost:6789" to connect to this JVM remotely to monitor how my

Page 42: Java Tools

PrimeNumberSeeker.java is running:

1. Run "jconsole localhost:6789". "jconsole" connects to my Java application correctly. The Java Monitoring & Management Console shows up.

2. Click the Memory tab, the memory usage detail information show up as shown in this picture:

Page 43: Java Tools

Chapter - 8'jstat' - JVM Statistics Monitoring Tool

This chapter provides tutorial notes on JVM statistics monitoring tools. Topics include listing JVM processes with 'jps', the JVM remote monitoring server - 'jstatd', Java security policy file, connecting 'jps' and 'jstat' to a remote machine, RMI protocol and URL, getting garbage collection statistics with 'jstat -gcutil'.

'jps' - JVM Process Status Tool

Listing JVM Processes on the Local Machine with "jps"

'jstatd' - JVM Remote Monitoring Server

Starting 'jstatd' with a Security Policy File

Connecting to 'jps' to Remote 'jstatd'

'jstat' Command Options and Parameters

Garbage Collection Testing Program

'jstat -gcutil' - Garbage Collection Statistics

Accessing Remote JVM Processes with 'jstat'

Conclusions:

• JDK 1.6 offers 3 nice JVM monitoring tools: jps, jstatd, and jstat. • jps is simple tool that allows you to list all running JVM processes on the local machine or a

remote machine. • jstatd is an RMI server that allows you to access local JVM processes by jps and jstat from

remote machines. • jstat is a monitoring tool that allows you to obtain sample data periodically from a local or

remote JVM process.

'jps' - JVM Process Status Tool

"jps": A new Java tool that lists all JVM processes on the local machine or a remote machine. "jps" tool is distributed as part of the Sun JDK package and represented by the \Progra~1\java\jdk1.6.0_02\bin\jps.exe program file. "jps" can be executed with the following syntax: jps [options] [hostid]

where "options" is a list of options and "hostid" is the host identifier of a remote machine.

"jps" options are listed below:

• -l Output the full package name for the application's main class or the full path name to the application's JAR file.

• -m Output the arguments passed to the main method. The output may be null for embedded JVMs.

• -q Suppress the output of the class name, JAR file name, and arguments passed to the main

Page 44: Java Tools

method, producing only a list of local VM identifiers. • -v Output the arguments passed to the JVM. • -Joption Pass option to the java launcher called by jps. For example, -J-Xms48m sets the startup

memory to 48 megabytes. It is a common convention for -J to pass options to the underlying VM executing applications written in Java.

You don't need to use the "hostid" command argument, if you want to list JVM processes on the local machine. But to list JVM processes on a remote, you need to use "hostid" to specify how to connect to the remove machine. The "hostid" is a string with the following syntax: [protocol:][[//]hostname][:port][/servername]

protocol The communications protocol. The default protocol is "rmi".

hostname A hostname or IP address indicating the remote host. port The default port for communicating with the remote server. The default port is the RMI registry port (1099). servername The treatment of this parameter depends on the implementation. For the "rmi" protocol, this parameter is a string representing the name of the RMI remote object on the remote host.

See sections below for tutorial examples on how to use "jps" to list JVM processes on the local or a remote machine.

Listing JVM Processes on the Local Machine with "jps"

It is very easy to listing JVM processes on the local machine using the "jps" tool. Here is what I did:

1. Run the PrimeNumberSeeker.java program I wrote in another tutorial in a command window: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\javac PrimeNumberSeeker.java

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\java PrimeNumberSeeker 10 200

Period, Current int, # primes1, 2, 02, 12, 53, 21, 8...

2. While PrimeNumberSeeker.java is running to search for prime numbers, run the "jps" tool in another command window: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m -v

2836 PrimeNumberSeeker 10 2003812 sun.tools.jps.Jps -l -m -v -Dapplication.home=C:\Program Files\java\jdk1.6.0_02 -Xms8m

Page 45: Java Tools

Several interesting notes on the "jps" output:

• Each JVM process is represented by starting class running in side the JVM. • The number displayed before the class name is the process ID. • When you run "jps", it starts a JVM process, which is also listed in the "jps" output. • The package name, "sun.tools.jps", is displayed because of the "-l" option. • The arguments passed to the main method, "10 200", are displayed because of the "-m" option. • The parameters passed to the JVM, "-D... -X...", are displayed because of the "-v" option.

'jstatd' - JVM Remote Monitoring Server

"jstatd": A server that allows JVM monitoring tools like "jps" and "jstat" to access JVM processes from a remote machine. "jstatd" tool is distributed as part of the Sun JDK package and represented by the \Progra~1\java\jdk1.6.0_02\bin\jstatd.exe program file. "jstatd" can be executed with the following syntax: jstatd [options]

"jstatd" options are listed below:

• "-p port" Port number where the RMI registry is expected to be found. If not found, an internal RMI registry will be created with this port number.

• "-n rminame" Name to which the remote RMI object is bound in the RMI registry. The default name is JStatRemoteHost.

After "jstatd" is started, JVM monitoring tools, "jps" and "jstat", can connect to it from a remote machine and access local JVM processes as shown in the picture below:

See next section on how to start "jstatd".

Starting 'jstatd' with a Security Policy File

In this tutorial, we are going to try to start the JVM remote monitoring server, "jstatd".

1. Run the "jstatd" command in a command window:

Page 46: Java Tools

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jstatd

Could not create remote objectaccess denied (java.util.PropertyPermission java.rmi.server.ignoreSubClasses write)java.security.AccessControlException: access denied (java.util.PropertyPermission java.rmi.server.ignoreSubClasses write)

at java.security.AccessControlContext.checkPermission (AccessControlContext.java:323) at java.security.AccessController.checkPermission (AccessController.java:546) at java.lang.SecurityManager.checkPermission (SecurityManager.java:532) at java.lang.System.setProperty(System.java:727) at sun.tools.jstatd.Jstatd.main(Jstatd.java:122)

The "access denied" error is expected, because "jstatd" requires a security policy file specified with the "java.security.policy" system property, if there is no security manager running on my machine.

2. Create the security policy file, tools.policy, that grants permissions to run "jstatd" and other tools in the tools.jar: grant codebase "file:${java.home}/../lib/tools.jar" { permission java.security.AllPermission;};

3. Run "jstatd" with the security policy file, tools.policy specified to the "java.security.policy" system property: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jstatd -p 1234 -J-Djava.security.policy=tools.policy

"jstatd" is running correctly now. It created an internal RMI registry and waiting at port 1234 for RMI protocol connections from remote machines by JVM monitoring tools. See the next section on how to run "jps" and "jstat" tools from remote machines.

Connecting to 'jps' to Remote 'jstatd'

With the "jstatd" server running on my local machine as described in the previous section, now I am ready to test how to connect to this "jstatd" server with the "jps" command from a remote machine to list JVM processes.

1. Run my test Java program PrimeNumberSeeker.java in another command window on my local machine: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\java PrimeNumberSeeker 10 200

Period, Current int, # primes1, 2, 02, 10, 4...

Page 47: Java Tools

2. Run the "jps" command to connect to the "jstatd" server with the "rmi://localhost" URL as the host identifier: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m -v rmi://localhost

RMI Registry not available at localhost:1099Connection refused to host: localhost; nested exception is: java.net.ConnectException: Connection refused: connect

3. The cause of the error is obvious, the "jstatd" server started the internal RMI registry at the port 1234, not the default port 1099. So Run the "jps" command again with the "rmi://localhost:1234": C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m -v rmi://localhost:1234

3056 sun.tools.jstatd.Jstatd -p 1234 -Dapplication.home=C:\jdk -Xms8m -Djava.security.policy=tools.policy4080 sun.tools.jps.Jps -l -m -v rmi://localhost:1234 -Dapplication.home=C:\Program Files\java\jdk1.6.0_02 -Xms8m2024 PrimeNumberSeeker 10 200

Cool. The "jps" successfully connected to the RMI registry through the "jstatd" server. The output shows correctly all running JVM processes.

'jstat' Command Options and Parameters

"jstat": A JVM statistics monitoring tool that displays performance statistics of a given JVM process with a specified sampling interval. "jstat" tool is distributed as part of the Sun JDK package and represented by the \Progra~1\java\jdk1.6.0_02\bin\jstat.exe program file. "jstat" can be executed with the following syntax: jstat [options] vmid interval [count]

• "options" - List of "jstat" command options. • "vmid" - Virtual machine identifier string to identify a local or a remote JVM process. • "interval" - Sampling interval in seconds (s) or mimilliseconds (ms). • "count" - Number of samples to collect. Default value is infinity; that is, jstat displays statistics

until the target JVM terminates or the jstat command is terminated.

Some "jstat" options are listed below:

• "-t" - Display a timestamp column as the first column of output. The timestamp is the the time since the start time of the target JVM.

• "-class" - Display multiple columns of statistics on the behavior of the class loader. • "-compiler" - Display multiple columns of statistics of the behavior of the HotSpot Just-in-Time

compiler. • "-gc" - Display multiple columns of statistics of the behavior of the garbage collected heap. • "-gcutil" - Display multiple columns of summary of garbage collection statistics. • "-gccapacity" - Display multiple columns of statistics of the capacities of the generations and

their corresponding spaces.

See the next section on how to use "jstat" to collect statistic samples of a given JVM process.

Page 48: Java Tools

Garbage Collection Testing Program

Since most of "jstat" options are about garbage collection statistics, I wrote this garbage collection testing program to test the "jstat" tool: /** * GarbageCollection.java * Copyright (c) 2008 by Dr. Herong Yang, http://www.herongyang.com/ */class GarbageCollection { public static void main(String[] a) { int max = 10000; int min = 16; Object[] arr = new Object[min]; Runtime rt = Runtime.getRuntime(); System.out.println("Free/total memory:"); for (int m=0; m<max; m++) { for (int n=0; n<min-1; n++) arr[min-n-1] = arr[min-n-2]; arr[0] = getOneMega(); System.out.println(rt.freeMemory()+" "+rt.totalMemory()); try { Thread.sleep(1000/10); } catch (InterruptedException e) { System.out.println("Interreupted..."); } } } private static Object getOneMega() { // return new long[1024*128]; // 1MB Object[] lst = new Object[10]; lst[0] = new long[256*128]; lst[1] = new int[256*256]; lst[2] = new double[256*128]; lst[3] = new float[64*256]; lst[4] = new byte[64*1024]; String[] l = new String[64*64]; for (int i=0; i<64*64; i++) l[i] = new String("12345678"); // 16B lst[5] = l; lst[6] = new char[64*512]; return lst; }}

When I run this program, I get this output: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\javac GarbageCollection.java

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\java -Xms24m -Xmx24m GarbageCollection

Free/total memory:23725256 2503475222710400 2503475221618728 2503475220523584 25034752

Page 49: Java Tools

19429328 2503475218330752 2503475217237416 2503475216137560 2503475215040664 2503475213943848 2503475212843752 2503475211747448 2503475210650832 25034752 9552096 25034752 8452192 25034752 7357216 25034752 6258720 25034752 5159112 25034752 4060976 25034752 2965296 25034752 1865656 25034752 767256 25034752 7356032 25034752 // Garbage Collection 6257576 25034752 5159368 25034752 4060712 25034752 2964336 25034752 1867032 25034752 767176 25034752 7356512 25034752 // Garbage Collection 6258136 25034752 5159360 25034752 4060464 25034752 2964064 25034752 1866728 25034752 766568 25034752 7356272 25034752 // Garbage Collection...

The output shows that the garbage collector is working correctly to remove those objects shifted out of the arr[].

'jstat -gcutil' - Garbage Collection Statistics

With the garbage collection testing program running, I am ready to test the "jstat" tool. The first test is run "jstat" with the "-gcutil -t" option to get statistic samples on a local JVM process.

1. Run the "jps" to get the process ID of the GarbageCollection.java JVM: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m -v

3824 sun.tools.jps.Jps -l -m -v -Dapplication.home=C:\Program Files\java\jdk1.6.0_02 -Xms8m3868 GarbageCollection -Xms24m -Xmx24m2924 PrimeNumberSeeker 10 2002544 sun.tools.jstatd.Jstatd -p 1234 -Dapplication.home=C:\jdk -Xms8m -Djava.security.policy=tools.policy

2. Run the "jstat" to get the summary of garbage collection statistics of the GarbageCollection JVM

Page 50: Java Tools

identified by the process ID 3868: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jstat -gcutil -t 3868 1s 30

Time S0 S1 E O P YGC YGCT FGC FGCT GCT313.7 0.00 99.99 4.20 84.56 0.15 2093 3.653 416 13.998 17.651314.6 0.00 99.99 0.00 97.66 0.15 2100 3.665 417 14.023 17.688315.6 0.00 0.00 0.00 71.25 0.15 2106 3.674 419 14.090 17.764316.7 0.00 99.99 4.20 84.56 0.15 2113 3.687 420 14.124 17.811317.7 0.00 99.99 0.00 97.66 0.15 2120 3.699 421 14.158 17.858318.6 0.00 0.00 0.00 71.25 0.15 2126 3.708 423 14.225 17.933319.7 0.00 99.99 4.20 84.56 0.15 2133 3.721 424 14.259 17.980320.7 0.00 99.99 0.00 97.66 0.15 2140 3.734 425 14.293 18.027321.6 0.00 0.00 0.00 71.25 0.15 2146 3.743 427 14.360 18.103322.7 0.00 99.99 4.20 84.56 0.15 2153 3.756 428 14.394 18.149323.7 0.00 99.99 0.00 97.66 0.15 2160 3.769 429 14.428 18.196324.7 0.00 0.00 67.14 71.25 0.15 2166 3.777 431 14.495 18.272325.7 0.00 99.99 4.20 84.56 0.15 2173 3.790 432 14.528 18.319326.7 0.00 99.99 0.00 97.66 0.15 2180 3.803 433 14.563 18.366327.7 0.00 99.99 86.29 97.66 0.15 2185 3.810 434 14.588 18.397328.7 99.99 0.00 0.00 77.66 0.15 2192 3.821 436 14.656 18.476329.7 0.00 99.99 71.29 84.56 0.15 2198 3.832 437 14.690 18.522330.7 0.00 99.99 19.15 97.66 0.15 2205 3.845 438 14.723 18.568331.7 99.99 0.00 0.00 77.66 0.15 2212 3.855 440 14.791 18.646332.7 0.00 99.99 71.29 84.56 0.15 2218 3.867 441 14.825 18.692...

The last two parameters "1s 30" tells "jstat" to collect 30 samples with an interval of 1 second.

To understand the statistic output, you need to read the full documentation of the "jstat" tool.

Accessing Remote JVM Processes with 'jstat'

In the previous section, I used the "jstat" tool to get garbage collection statistic against a JVM process on the local machine.

Now I want to use the "jstat" tool to get garbage collection statistic against a JVM process on a remote machine. Like the "jps" tool, the "jstat" tool also requires that the remote machine running the "jstatd" server with a RMI registry.

1. Make sure that the "jstatd" server is running on the remote machine: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jstatd -p 1234 -J-Djava.security.policy=tools.policy

2. Make sure that the garbage collection program is running on the remote machine: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\java -Xms24m -Xmx24m GarbageCollection

Free/total memory:23725256 2503475222710400 25034752...

Page 51: Java Tools

3. Run the "jps" tool to get a list of JVM process IDs on the remote machine: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m -v rmi://localhost:1234

2924 PrimeNumberSeeker 10 2002544 sun.tools.jstatd.Jstatd -p 1234 -Dapplication.home=C:\jdk -Xms8m -Djava.security.policy=tools.policy3028 sun.tools.jps.Jps -l -m -v rmi://localhost:1234 -Dapplication.home=C:\Program Files\java\jdk1.6.0_02 -Xms8m3536 GarbageCollection -Xms24m -Xmx24m

4. I am ready to run the "jstat" tool to get some statistics data on the garbage collection program: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jstat -gcutil -t rmi://3536@localhost:1234 1s 30

Time S0 S1 E O P YGC YGCT FGC FGCT GCT303.6 0.00 99.99 86.29 97.66 0.15 2025 3.589 402 13.500 17.089304.6 99.99 0.00 35.16 77.66 0.15 2032 3.597 404 13.559 17.155305.6 100.00 0.00 51.20 90.69 0.15 2039 3.610 405 13.592 17.202...

Cool. The "jstat" tool works nicely to get statistics data from a JVM process on a remote machine.

Page 52: Java Tools

Chapter - 9JVM Troubleshooting Tools

This chapter tutorial notes on JVM troubleshooting tools. Topics include 'jinfo' to check JVM option values, 'jstack' to dump stack traces and detect deadlocks, 'jmap' to print heap histogram and dump heap files, 'jhat' to browse head files and run OQL queries.

JVM Troubleshooting Tools in JDK 1.5

'jinfo' - VM Option Value Checker

Changing HotSpot VM Option using 'jinfo'

'jstack' - Stack Tracer of JVM Threads

Java Thread Deadlock Demo Program

Detecting Java Thread Deadlocks with 'jstack'

'jmap' - JVM Heap Dump Tool

Printing Histogram of Java Object Heap

Generating Heap Dump File with 'jmap'

'jhat' - Java Heap Analysis Tool

Starting 'jhat' Web Server on a Heap Dump File

Listing Instance Counts of All Classes

Browsing Object Instance Values

Object Query Language (OQL)

Searching for Instances with OQL Statements

Conclusions:

• JDK 1.6 offers a number of nice trouble shooting tools: jinfo, jstack, jmap, and jhat. • jinfo allows you to check current VM options of a running JVM process. • jstack allows you to dump thread stack traces and find any deadlocks. • jmap allows you to print heap memory usages and instance counts by classes and dump the

entire heap to a file. • jhat allows you to browse a heap dump file with a Web interface. • jhat also supports OQL (Object Query Language) statements - a very powerful tool to

investigate any data issues in your Java application.

JVM Troubleshooting Tools in JDK 1.5

If you look at Java tools section of the JDK 1.5 documentation page, you will see a group of new experimental tools called "Troubleshooting Tools":

"jinfo": Prints configuration information for a given JVM process or a Java core file on the local machine or on a remote machine through a debug server.

Page 53: Java Tools

"jhat" - Heap Dump Browser: Starts a Web server on a Java heap dump file (eg, produced by "jmap -dump"), allowing the heap to be browsed.

"jmap" - Memory Map: Prints shared object memory maps or heap memory details of a given JVM process or a Java core file on the local machine or on a remote machine through a debug server.

"jsadebugd" - Serviceability Agent Debug Daemon: Attaches to a JVM process or a Java core file and acts as a debug server for remote tools to connect.

"jstack" - Stack Trace: Prints a stack trace of threads for a given JVM process or a Java core file on the local machine or on a remote machine through a debug server.

Note that not all functions described above are available on Windows systems. See next sections on how to use those tools provided in JDK 1.6 on a Windows system.

'jinfo' - VM Option Value Checker

The first JVM troubleshooting tool I want try is the "jinfo" tool.

The "jinfo" tool included in the Windows version of JDK 1.6 only supports functions to view and modify HotSpot VM options of the specified JVM process. Here is the "jinfo" command syntax: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jinfo

Usage: jinfo <option> <pid> (to connect to a running process)

where <option> is one of: -flag <name> to print the value of the named VM option -flag [+|-]<name> to enable or disable the named VM option -flag <name>=<value> to set the named VM option to the given value -h | -help to print this help message

HotSpot VM supports many options as described on the "Java HotSpot VM Options" page. You can change the default value of any HotSpot VM option using the "-XX:..." command option when running the "java" command.

Here is a tutorial example of how to use the "jinfo" tool get the current value of a given VM option: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\java -jar "\Program Files\java\jdk1.6.0_02\demo\jfc\Notepad\notepad.jar" (Notepad started.)

(Start another command window.)C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m

424 \Program Files\java\jdk1.6.0_02\demo\jfc\Notepad\notepad.jar3984 sun.tools.jps.Jps -l -m

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jinfo -flag ThreadStackSize 424

-XX:ThreadStackSize=0

Page 54: Java Tools

Note that:

• The "jps" tool is used to get the process ID (pid) of the Notepad JVM: 424. • The output of the "jinfo" command shows that the current value of the ThreadStackSize option

is 0 in the Notepad JVM.

Changing HotSpot VM Option using 'jinfo'

The "jinfo" tool can be used to view the current value of any HotSpot VM option of a given JVM process as described in the previous section.

The "jinfo" tool can also be used set a new value of any HotSpot VM option using the "jinfo -flag name=value" format. Here is what I did to test this function with JDK 1.6 on a Windows system: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\java -XX:ThreadStackSize=512 -jar "\Program Files\java\jdk1.6.0_02\demo\jfc\Notepad\notepad.jar" (Notepad started)

(Start another command window.)C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m

1424 \Program Files\java\jdk1.6.0_02\demo\jfc\Notepad\notepad.jar3124 sun.tools.jps.Jps -l -m

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jinfo -flag ThreadStackSize 1424

-XX:ThreadStackSize=512

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jinfo -flag ThreadStackSize=1024 1424 Exception in thread "main" java.io.IOException: Command failed in target VM at sun.tools.attach.WindowsVirtualMachine.execute (WindowsVirtualMachine.java:94) at sun.tools.attach.HotSpotVirtualMachine.executeCommand (HotSpotVirtualMachine.java:195) at sun.tools.attach.HotSpotVirtualMachine.setFlag (HotSpotVirtualMachine.java:172) at sun.tools.jinfo.JInfo.flag(JInfo.java:105) at sun.tools.jinfo.JInfo.main(JInfo.java:58)

Apparently, the target VM (the Notepad VM) does not allow me to change its option. I do not know why?

'jstack' - Stack Tracer of JVM Threads

"jstack": A JVM troubleshooting tool that prints stack traces of all running threads of a given JVM process, a Java core file, or remote debug server. The "jstack" tool included in the JDK 1.6 Windows version only supports limited functions as shown the this help message:

Page 55: Java Tools

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jstack -help

Usage: jstack [-l] <pid> (to connect to running process)

Options: -l long listing. Prints additional information about locks -h or -help to print this help message

In order to test "jstack", I used this simple Java program, LongSleep.java: /** * LongSleep.java * Copyright (c) 2008 by Dr. Herong Yang, http://www.herongyang.com/ */class LongSleep { public static void main(String[] a) { Runtime rt = Runtime.getRuntime(); System.out.println(" Free memory: " + rt.freeMemory()); System.out.println("Total memory: " + rt.totalMemory()); try {Thread.sleep(1000*60*60);} catch (InterruptedException e) {} }}

When LongSleep.java is running, I used "jps" to get its JVM process ID, pid. Then I ran "jstack" with that pid to get the following stack information: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\javac LongSleep.java

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\java LongSleep Free memory: 4997104Total memory: 5177344

(Start another command window.)C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m3296 LongSleep2224 sun.tools.jps.Jps -l -m

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jstack 3296

Full thread dump Java HotSpot(TM) Client VM (1.6.0_02-b06 mixed mod...

"Low Memory Detector" daemon prio=6 tid=0x02a7c800 nid=0xf20 runnable java.lang.Thread.State: RUNNABLE

"CompilerThread0" daemon prio=10 tid=0x02a78000 nid=0xb3c waiting ... java.lang.Thread.State: RUNNABLE

"Attach Listener" daemon prio=10 tid=0x02a76c00 nid=0x37c waiting ... java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x02a75c00 nid=0xd7c runnable java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=8 tid=0x02a71400 nid=0x2e8 in Object.wait()

Page 56: Java Tools

java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x22990b38> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) - locked <0x22990b38> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x02a6d000 nid=0xfbc in Obje... java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x22990a38> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:485) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116) - locked <0x22990a38> (a java.lang.ref.Reference$Lock)

"main" prio=6 tid=0x00296000 nid=0xef4 waiting on condition [0x0090... java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at LongSleep.main(LongSleep.java:10)

"VM Thread" prio=10 tid=0x02a63c00 nid=0xc70 runnable

"VM Periodic Task Thread" prio=10 tid=0x02a7e000 nid=0xdd0 waiting ...

JNI global references: 571

Cool. Now I know how many threads are running inside a JVM, 8 of them. But my Java application, LongSleep, only runs under 1 thread named as "main", which is in a state called, TIMED_WAITING. This matches my expectation.

Java Thread Deadlock Demo Program

In the previous section, "jstack" was used to print stack traces of all running threads of a given JVM process. But "jstack" can also be used to detect deadlocks inside a given JVM process. The tutorial example below shows you how "jstack" prints deadlock information:

1. Copy and save this Java program, /** * SimpleDeadLock.java * Copyright (c) 2008 by Dr. Herong Yang, http://www.herongyang.com/ */import java.util.*;public class SimpleDeadLock extends Thread { public static Object l1 = new Object(); public static Object l2 = new Object(); private int index; public static void main(String[] a) { Thread t1 = new Thread1(); Thread t2 = new Thread2(); t1.start(); t2.start(); } private static class Thread1 extends Thread { public void run() { synchronized (l1) {

Page 57: Java Tools

System.out.println("Thread 1: Holding lock 1..."); try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println("Thread 1: Waiting for lock 2..."); synchronized (l2) { System.out.println("Thread 2: Holding lock 1 & 2..."); } } } } private static class Thread2 extends Thread { public void run() { synchronized (l2) { System.out.println("Thread 2: Holding lock 2..."); try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println("Thread 2: Waiting for lock 1..."); synchronized (l1) { System.out.println("Thread 2: Holding lock 2 & 1..."); } } } }}

2. Compile and run SimpleDeadLock.java. A deadlock will be created immediately between two running threads: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\javac SimpleDeadLock.java

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\java SimpleDeadLock

Thread 1: Holding lock 1...Thread 2: Holding lock 2...Thread 2: Waiting for lock 1...Thread 1: Waiting for lock 2...

This deadlock is expected - Thread 1 is holding lock 1 and waiting for lock 2, while thread 2 is holding lock 2 and waiting for lock 1.

See the next section on how to use "jstack" to print the deadlock information and stack traces of 2 related threads.

Detecting Java Thread Deadlocks with 'jstack'

This section provides a tutorial example on how to detect Java thread deadlocks with the thread stack trace dump tool, 'jstack'.

With the deadlock demo program, SimpleDeadLock.java, running in a locked status as described in the previous section, I am ready to run "jstack" to print the deadlock information and stack traces of 2 locked threads: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m1464 SimpleDeadLock

Page 58: Java Tools

464 sun.tools.jps.Jps -l -m

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jstack 1464

Full thread dump Java HotSpot(TM) Client VM (1.6.0_02-b06 mixed mod...

"DestroyJavaVM" prio=6 tid=0x00296000 nid=0x198 waiting on conditio... java.lang.Thread.State: RUNNABLE

"Thread-1" prio=6 tid=0x02a99c00 nid=0xee0 waiting for monitor entr... java.lang.Thread.State: BLOCKED (on object monitor) at SimpleDeadLock$Thread2.run(SimpleDeadLock.java:37) - waiting to lock <0x229bd238> (a java.lang.Object) - locked <0x229bd240> (a java.lang.Object)

"Thread-0" prio=6 tid=0x02a99000 nid=0xefc waiting for monitor entr... java.lang.Thread.State: BLOCKED (on object monitor) at SimpleDeadLock$Thread1.run(SimpleDeadLock.java:24) - waiting to lock <0x229bd240> (a java.lang.Object) - locked <0x229bd238> (a java.lang.Object)

"Low Memory Detector" daemon prio=6 tid=0x02a7c800 nid=0xd2c runnab... java.lang.Thread.State: RUNNABLE

"CompilerThread0" daemon prio=10 tid=0x02a78000 nid=0x500 waiting o... java.lang.Thread.State: RUNNABLE

"Attach Listener" daemon prio=10 tid=0x02a76c00 nid=0x32c waiting o... java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x02a75c00 nid=0x190 runnabl... java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=8 tid=0x02a6e000 nid=0xdb0 in Object.wait()... java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x22990b38> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) - locked <0x22990b38> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x02a6d000 nid=0xa44 in Obje... java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x22990a38> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:485) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116) - locked <0x22990a38> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=10 tid=0x02a63c00 nid=0xe88 runnable

"VM Periodic Task Thread" prio=10 tid=0x02a7e000 nid=0xf58 waiting ...

JNI global references: 571

Found one Java-level deadlock:

Page 59: Java Tools

============================="Thread-1": waiting to lock monitor 0x02a6ee64 (object 0x229bd238, a java.lang.Object), which is held by "Thread-0""Thread-0": waiting to lock monitor 0x02a6eecc (object 0x229bd240, a java.lang.Object), which is held by "Thread-1"

Java stack information for the threads listed above:==================================================="Thread-1": at SimpleDeadLock$Thread2.run(SimpleDeadLock.java:37) - waiting to lock <0x229bd238> (a java.lang.Object) - locked <0x229bd240> (a java.lang.Object)"Thread-0": at SimpleDeadLock$Thread1.run(SimpleDeadLock.java:24) - waiting to lock <0x229bd240> (a java.lang.Object) - locked <0x229bd238> (a java.lang.Object)

Found 1 deadlock.

The output of "jstack" is very useful for debugging. It tells me:

• How many deadlocks exist in this JVM process. • What are the 2 waiting threads for each deadlock. • Stack traces of waiting threads with source code line numbers, if source codes were compile

with debug options.

'jmap' - JVM Heap Dump Tool

"jmap" - Memory Map: Prints shared object memory maps or heap memory details of a given JVM process or a Java core file on the local machine or on a remote machine through a debug server. "jmap" supports several functions with these syntaxes: jmap [ option ] pidjmap [ option ] executable corejmap [ option ] [server-id@]remote-hostname-or-IP

<no option> When no option is used jmap prints shared object mappings. For each shared object loaded in the target VM, start address, the size of the mapping, and the full path of the shared object file are printed. This is similar to the Solaris pmap utility.

-dump:[live,]format=b,file=<filename> Dumps the Java heap in hprof binary format to filename. The live suboption is optional. If specified, only the live objects in the heap are dumped. To browse the heap dump, you can use jhat (Java Heap Analysis Tool) to read the generated file.

-finalizerinfo Prints information on objects awaiting finalization.

-heap Prints a heap summary. GC algorithm used, heap configuration and generation wise heap usage are printed.

Page 60: Java Tools

-histo[:live] Prints a histogram of the heap. For each Java class, number of objects, memory size in bytes, and fully qualified class names are printed. VM internal class names are printed with '*' prefix. If the live suboption is specified, only live objects are counted.

-permstat Prints class loader wise statistics of permanent generation of Java heap. For each class loader, its name, liveness, address, parent class loader, and the number and size of classes it has loaded are printed. In addition, the number and size of interned Strings are printed.

-F Force. Use with jmap -dump or jmap -histo option if the pid does not respond. The live suboption is not supported in this mode.

But the "jmap" tool included in the Windows version of JDK 1.6 only supports functions to print histogram of Java object heap and generate a heap dump of a given JVM process: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jmap

Usage: jmap -histo <pid> (to print histogram of java object heap of the JVM process) jmap -dump:<dump-options> <pid> (to dump java heap of the JVM process)

dump-options: format=b binary default file=<file> dump heap to <file>

Example: jmap -dump:format=b,file=heap.bin <pid>

See the next section on how to use "jmap" to print heap histogram and to generate heap dump.

Printing Histogram of Java Object Heap

The first function of the "jmap" tool is to print histogram of object heap of a given JVM process. Now I am going to use a sample Java program, GarbageCollection.java, I wrote in another tutorial example in this book.

The first test is to print the heap histogram of a JVM process that runs GarbageCollection.java with the "jmap -histo pid" command: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\javac GarbageCollection.java

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\java -Xms24m -Xmx24m GarbageCollection

Free/total memory:23725256 2503475222710400 2503475221618728 2503475220523584 25034752...

Page 61: Java Tools

(Start another command window.)C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m

492 sun.tools.jps.Jps -l -m428 GarbageCollection

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jmap -histo 428

num #instances #bytes class name-------------------------------------- 1: 23 4723136 [I 2: 19 4718928 [J 3: 18 4718880 [D 4: 73925 1774200 java.lang.String 5: 208 1226400 [C 6: 28 1205064 [B 7: 18 1179936 [F 8: 68 297040 [Ljava.lang.String; 9: 332 14136 [Ljava.lang.Object; 10: 32 10240 <objArrayKlassKlass> 11: 42 4032 java.lang.Class 12: 58 1392 java.util.Hashtable$Entry 13: 16 1280 [Ljava.util.HashMap$Entry; 14: 27 1000 <symbolKlass> 15: 6 864 [S 16: 7 680 [Ljava.util.Hashtable$Entry; 17: 11 616 java.net.URL 18: 19 608 java.util.Locale 19: 5 560 java.lang.Thread 20: 14 560 java.util.HashMap...

The histogram gives a very good summary of heap objects used in my GarbageCollection.java program:

• Most of the objects were String objects. There were 73925 of them. This matches well with what I allocated in the program: one array of 64*64 string objects for each 1-MB object. If 16 1-MB objects were allocated, there should be 65536 string objects.

• "[Ljava.lang.String;" is a special class name representing a java.lang.String[] array. • "[I" is a special class name representing a int[] array.

Generating Heap Dump File with 'jmap'

The second function of the "jmap" tool is to generate a heap dump of a given JVM process with the "jmap -dump:file=<filename>" command: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\java -Xms24m -Xmx24m GarbageCollection

Free/total memory:23725256 2503475222710400 2503475221618728 2503475220523584 25034752

Page 62: Java Tools

...

(Start another command window.)C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m

764 GarbageCollection1204 sun.tools.jps.Jps -l -m

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jmap -dump:file=GarbageCollection.map 764

Dumping heap to C:\herong\GarbageCollection.map ...Heap dump file created

C:\herong>dir *.map

12:08 AM 19,816,895 GarbageCollection.map

So the heap dump file, "GarbageCollection.map", is a snapshot of all heap objects used by the running GarbageCollection.java process.

Heap dump files can be browsed by the heap dump browser, "jhat", as described in the next section.

'jhat' - Java Heap Analysis Tool

"jhat" - Java heap analysis tool or heap dump file browser: Parses a Java heap dump file and launches a Web server. "jhat" enables you to browse heap dump files using your favorite webbrowser. "jhat" supports pre-designed queries (such as 'show all instances of a known class "Foo"') as well as OQL (Object Query Language) - a SQL-like query language to query heap dumps. Help on OQL is available from the OQL help page shown by "jhat". With the default port, OQL help is available at http://localhost:7000/oqlhelp/

But the "jmap" tool included in the Windows version of JDK 1.6 only supports functions to print histogram of Java object heap and generate a heap dump of a given JVM process: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jhat -help

Usage: jhat [-stack <bool>] [-refs <bool>] [-port <port>] [-baseline <file>] [-debug <int>] [-version] [-h|-help] <file>

-stack false Turn off tracking object allocation call stack. -refs false Turn off tracking of references to objects -port <port> Set the port for the HTTP server. Default is 7000. -exclude <file> Specify a file that lists data members that should be excluded from the reachableFrom query. -baseline <file> Specify a baseline object dump. Objects in both heap dumps with the same ID and same class will be marked as not being "new". -debug <int> Set debug level. 0: No debug output 1: Debug hprof file parsing 2: Debug hprof file parsing, no server -version Report version number -h|-help Print this help and exit

Page 63: Java Tools

<file> The file to read

For a dump file that contains multiple heap dumps,you may specify which dump in the fileby appending "#<number>" to the file name, i.e. "foo.hprof#3".

All boolean options default to "true"

Starting 'jhat' Web Server on a Heap Dump File

In an earlier tutorial example, I created a Java heap dump file with the "jmap" tool on my GarbageCollection.java program. The heap dump file is named as GarbageCollection.map. Now I want to try to run the "jhat" Web server on this dump file and browse the heap dump with a Web browser.

1. Run the "jhat" command with default options: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jhat GarbageCollection.map

Reading from GarbageCollection.map...Dump file created Jan 1 00:08:10 EDT 2008Snapshot read, resolving...Resolving 67324 objects...Chasing references, expect 13 dots.............Eliminating duplicate references.............Snapshot resolved.Started HTTP server on port 7000Server is ready.

2. Run a Web browser with http://localhost:7000. The "jhat" heap dump file server page shows up:

See next sections on how to use "jhat" Web server to browse heap objects.

Page 64: Java Tools

Listing Instance Counts of All Classes

Running "jhat" Web server on a heap dump file offers us a very good debugging tool. You can get statistical counts of loaded classes and objects. You can review object contents and references. You can also run object queries to search for any specific information.

First, let's see how to get instance counts for all loaded classes.

1. Run a Web browser with http://localhost:7000. The heap dump first page shows up.

2. Click the link of "Show instance counts for all classes (including platform)". The instance count page shows up: 65733 instances of class java.lang.String 362 instances of class java.lang.Class 330 instances of class [Ljava.lang.Object; 206 instances of class [C 66 instances of class [Ljava.lang.String; 58 instances of class java.util.Hashtable$Entry 50 instances of class [I 26 instances of class [B 19 instances of class java.util.Locale 19 instances of class java.util.concurrent.ConcurrentHashMap$HashEntry 17 instances of class [J 16 instances of class java.util.HashMap$Entry 16 instances of class java.util.concurrent.ConcurrentHashMap$Segment 16 instances of class java.util.concurrent.locks.ReentrantLock$NonfairSync 16 instances of class [D 16 instances of class [F 16 instances of class [Ljava.util.HashMap$Entry; 16 instances of class [Ljava.util.concurrent.ConcurrentHashMap$HashEntry; 14 instances of class java.lang.Object 14 instances of class java.util.HashMap 14 instances of class java.util.LinkedHashMap$Entry 12 instances of class java.io.ExpiringCache$Entry 11 instances of class java.net.URL 10 instances of class java.io.ObjectStreamField ....

The output shows that the highest count is the number of java.lang.String instances. This is expected, because I created String arrays with 64*64 Strings in each array.

Browsing Object Instance Values

After looking object instance counts, I want to find some object instances created by my program and browse their values. My program, GarbageCollection.java, used the following code to create many java.lang.Object[] instances: private static Object getOneMega() { Object[] lst = new Object[10]; lst[0] = new long[256*128]; lst[1] = new int[256*256]; lst[2] = new double[256*128]; lst[3] = new float[64*256]; lst[4] = new byte[64*1024];

Page 65: Java Tools

String[] l = new String[64*64]; for (int i=0; i<64*64; i++) l[i] = new String("12345678"); // 16B lst[5] = l; lst[6] = new char[64*512]; return lst; }

I want to find one of these Object[] instances and review its elements.

1. Run a Web browser with http://localhost:7000. The heap dump first page shows up.

2. Click the link of "Show instance counts for all classes (including platform)". The instance count page shows up.

3. Click the link of "instances" in the line of "330 instances of class [Ljava.lang.Object;". Remember that "[Ljava.lang.Object;" is the class name for Object[] arrays. A list of all 330 instances is displayed with their addresses.

3. Click on the first instance of "[Ljava.lang.Object;@0x25a9e6d0 (48 bytes)". The contents of this instance show up: Object at 0x25a9e6d0

Array of 10 objects

Class:class [Ljava.lang.Object;

Values0 : [J@0x25aaea00 (262152 bytes) 1 : [I@0x25aeea10 (262152 bytes) 2 : [D@0x25b2ea20 (262152 bytes) 3 : [F@0x25b6ea30 (65544 bytes) 4 : [B@0x25b7ea40 (65544 bytes) 5 : [Ljava.lang.String;@0x25b8ea50 (16392 bytes) 6 : [C@0x25baa7b0 (65544 bytes) 7 : null8 : null9 : null

References to this object:[Ljava.lang.Object;@0x2536e920 (72 bytes) : Element 8 of [Ljava.lang.Object;@0x2536e920

Excellent! I am lucky that the first instance of Object[] is created by my code. "jhat" does a good job showing me everything about this instance. I can continue clicking its values or references to get information.

Conclusion: "jhat" is much easier to use than many Java debugger for browser heap objects.

Page 66: Java Tools

Object Query Language (OQL)

OQL (Object Query Language): A SQL-like query language to query Java heap. OQL allows to filter/select information wanted from Java heap. While pre-defined queries such as "show all instances of class X" are already supported by HAT, OQL adds more flexibility. OQL is based on JavaScript expression language.

OQL query is of the form" select <JavaScript expression to select> [ from [instanceof] <class name> <identifier> [ where <JavaScript boolean expression to filter> ] ]

where class name is fully qualified Java class name (example: java.net.URL) or array class name. [C is char array name, [Ljava.io.File; is name of java.io.File[] and so on. Note that fully qualified class name does not always uniquely identify a Java class at runtime. There may be more than one Java class with the same name but loaded by different loaders. So, class name is permitted to be id string of the class object. If instanceof keyword is used, subtype objects are selected. If this keyword is not specified, only the instances of exact class specified are selected. Both from and where clauses are optional.

In select and (optional) where clauses, the expression used in JavaScript expression. Java heap objects are wrapped as convenient script objects so that fields may be accessed in natural syntax. For example, Java fields can be accessed with obj.field_name syntax and array elements can be accessed with array[index] syntax. Each Java object selected is bound to a JavaScript variable of the identifier name specified in from clause.

OQL Examples: select all Strings of length 100 or more: select s from java.lang.String s where s.count >= 100

select all int arrays of length 256 or more: select a from [I a where a.length >= 256

show content of Strings that match a regular expression: select s.value.toString() from java.lang.String s where /java/(s.value.toString())

show path value of all File objects: select file.path.value.toString() from java.io.File file

show names of all ClassLoader classes: select classof(cl).name from instanceof java.lang.ClassLoader cl

show instances of the Class identified by given id string: select o from instanceof 0xd404b198 o

Note that 0xd404b198 is id of a Class (in a session). This is found by looking at the id shown in that class's page.

See next section on how to run OQL statements on the "jhat" Web server.

Page 67: Java Tools

Searching for Instances with OQL Statements

To test the power of OQL, I want to find those Object[] instances created by my program, excluding Object[] created by the JVM platform.

1. Run a Web browser with http://localhost:7000. The heap dump first page shows up.

2. Click the link of "Execute Object Query Language (OQL) query". The OQL query page shows up.

3. Enter the following query and click the Execute button: select i from [Ljava.lang.Object; i where i.length == 10

Cool. "jhat" returns a list of instances that matches my query condition:

But the previous OQL query is not good enough to return only Object[] instances I wanted. The query below will do a better job. Try it. select i from [Ljava.lang.Object; i where i.length == 10 && i[5] != null && classof(i[5]).name == '[Ljava.lang.String;'

Watch out the OQL statement syntax. It takes JavaScript expressions only, not SQL expressions.

Page 68: Java Tools

Chapter - 10'jar' - The JAR File Tool

This chapter provides notes and tutorials on JAR file tool, 'jar'. Topics include Java Archive (JAR) file forma, 'jar' command options, creating JAR files, managing JAR files with WinZIP, using manifest file, creating executable JAR files.

JAR - Java Archive File Format

'jar' - JAR File Tool Command and Options

Creating the First JAR File - hello.jar

Managing JAR Files with WinZIP

META-INF/MANIFEST.MF - JAR Manifest File

Adding META-INF/MANIFEST.MF to JAR Files

Using JAR Files in Java Class Paths

Creating Executable JAR Files

Conclusions:

• JAR files are ZIP files. • JAR files can have attributes stored in the META-INF/MANIFEST.MF file. • JAR files can be used in Java class paths. • JAR files can be "executable".

JAR - Java Archive File Format

JAR (Java Archive): A file format that compresses many files into a single package file. A JAR may contain additional package attributes and supporting data. It has some interesting features:

• It uses the standard ZIP algorithm for compression. • Package attributes and supporting data are stored as files in a special directory called META-

INF.

The main purpose of a JAR file is to aggregate your .class files, not your .java files, into a single file to distribute them to your customers. A JAR file can be directly included in the class path if you want to access those class files in the JAR file. No need to extract those class files into Java class directories.

Usually, JAR files are managed by the 'jar' tool provided in the JDK package.

But JAR files can also be managed by most ZIP tools, since JAR files are really ZIP files.

'jar' - JAR File Tool Command and Options

"jar": A command line tool for managing JAR files. "jar" is distributed as part of the Sun JDK package. It has some interesting features:

• It can create, update or extract a JAR file. • ZIP compression is optional.

Page 69: Java Tools

"jar" command syntax: Create jar file jar c[v0M]f jarfile inputfiles jar c[v0]mf manifest jarfile inputfiles

Update jar file jar u[v0M]f jarfile inputfilesjar u[v0]mf manifest jarfile inputfiles

Extract jar file jar x[v]f jarfile [inputfiles]

List table of contents of jar file jar t[v]f jarfile [inputfiles]

where:

• "c" - Creates a new JAR file. • "v" - Generates verbose output to standard output. • "0" - Specifies no compression. • "M" - Specifies no manifest file. • "f" - Specifies the JAR file name. • "m" - Specifies the manifest file name. • "u" - Updates a JAR file. • "x" - Extracts files out of a JAR file. • "t" - Displays the table of contents of a JAR file.

"jar" command is supported by the file, \j2sdk1.5.0\bin\jar.exe, if you installed JDK as in my previous chapter.

Creating the First JAR File - hello.jar

To create my first JAR file, I wrote the following Java file, Hello.java: class Hello { public static void main(String[] a) { System.out.println("Hello world!"); }}

Here is what I did in a command window to create and extract my first JAR file, hello.jar: C:\herong>javac Hello.java

C:\herong>jar cvf hello.jar Hello.classadded manifestadding: Hello.class(in = 416) (out= 285)(deflated 31%)

C:\herong>jar tf hello.jarMETA-INF/META-INF/MANIFEST.MFHello.class

>del Hello.class

C:\herong>jar xvf hello.jar created: META-INF/

Page 70: Java Tools

extracted: META-INF/MANIFEST.MFextracted: Hello.class

C:\herong>dir Hello.class 416 Hello.class

C:\herong>type meta-inf\manifest.mfManifest-Version: 1.0Created-By: 1.4.2 (Sun Microsystems Inc.)

What happened here is that:

• My first "jar" command created a new JAR file called hello.jar. "jar" automatically added "manifest".

• My second "jar" command displayed what is in hello.jar. As you can see, the first "jar" command actually added a directory called META-INF into the jar file.

• My third "jar" command extracted all files out of hello.jar. • My "type" command showed you what was added as "manifest": two package attributes:

version and create-by.

Managing JAR Files with WinZIP

The JAR specification says that "JAR file is a file format based on the popular ZIP file format". So are JAR files really ZIP files? Let's do some tests to find out.

Test 1. Create a JAR file, test.jar, with "jar" command. Rename test.jar to test.zip. Unzip test.zip with WinZIP. You should have no problem to extract all files out of test.zip with WinZIP.

Test 2. Create a ZIP file, tutu.zip, with WinZIP. Rename tutu.zip to tutu.jar. Extract files from tutu.jar with "jar". You should have no problem to extract all files out of tutu.jar with "jar" command.

Test 3. Create a password protected ZIP file, secure.zip, with WinZIP. Rename secure.zip to secure.jar. Extract files from secure.jar with "jar". You should get a run time exception like this: C:\herong>jar tf secure.jarjava.io.FileNotFoundException: secure.jar (The system cannot find the file specified) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.<init>(FileInputStream.java:106) at java.io.FileInputStream.<init>(FileInputStream.java:66) at sun.tools.jar.Main.run(Main.java:185) at sun.tools.jar.Main.main(Main.java:904)

So JAR files and ZIP files are fully compatible, as long as no encryptions are used on ZIP files.

I guess I don't need WinZIP anymore.

META-INF/MANIFEST.MF - JAR Manifest File

"manifest" in a JAR file is a file named as META-INF/MANIFEST.MF. It contains attributes about the JAR file and its contents.

Attributes in "manifest" are recorded as a list of name-value pairs in the form of "name: value\n". The

Page 71: Java Tools

list is divided into a main section for package-level attributes and multiple sub sections for entry-level attributes. Note that each attribute must be ended with a new line character.

The main section may contain only the package level attributes like:

• Manifest-Version • Created-By • Main-Class • Class-Path • Implementation-Vendor • Implementation-URL

Sub sections are optional. They are used to provide entry-level attributes with one section per entry. A sub sections must be preceded with a blank line and started with a "Name" attribute to associate this section with a content entry in the JAR file. Example of entry-level attributes are:

• Content-Type • Java-Bean

Adding META-INF/MANIFEST.MF to JAR Files

There are two ways to add "manifest" to a JAR file.

1. Adding "manifest" through "jar" command line. Store all your manifest attributes in a file. And specify this file in the "jar" command line with the "m" option: jar c[v0]mf manifest jarfile inputfiles

For example, I created my own manifest file called manifest.txt with one attribute in it: Main-Class: Hello

Remember to press the <Enter> key at the end of the attribute. This will insert a new line character (\n) to terminate the attribute.

Here is how I added my manifest to a JAR file with the "m" option: C:\herong>jar cvmf manifest.txt hello.jar Hello.classadded manifestadding: Hello.class(in = 416) (out= 285)(deflated 31%)

C:\herong>jar xvf hello.jar created: META-INF/extracted: META-INF/MANIFEST.MFextracted: Hello.class

C:\herong>type META-INF\MANIFEST.MFManifest-Version: 1.0Created-By: 1.4.2 (Sun Microsystems Inc.)Main-Class: Hello

As you can see that "jar" command copied the attribute from my manifest file to the end of the auto-generated MANIFEST.MF file.

Page 72: Java Tools

2. Adding "manifest" through META-INF/MANIFEST.MF file. Create META-INF/MANIFEST.MF as a text file. Enter all your manifest attributes in this file. And include META-INF/MANIFEST.MF as an input file to JAR file.

For example, I created my own META-INF/MANIFEST.MF with a text editor as: Manifest-Version: 3.3Created-By: Herong YangMain-Class: Hello

Here is how I added my manifest to a JAR file with the "M" option: C:\herong>jar cvMf tutu.jar Hello.class META-INFadding: Hello.class(in = 416) (out= 285)(deflated 31%)adding: META-INF/(in = 0) (out= 0)(stored 0%)adding: META-INF/MANIFEST.MF(in = 19) (out= 21)(deflated -10%)

C:\herong>jar tf tutu.jarHello.classMETA-INF/META-INF/MANIFEST.MF

Note that:

• The "M" option stops "jar" to auto-generate the META-INF/MANIFEST.MF file. • When MANIFEST.MF is included as an input file, it was compressed. This is different than the

auto-generated version, which was not compressed at all.

Using JAR Files in Java Class Paths

One advantage of aggregating individual class files into a JAR file is that other Java tools recognize JAR files as collections of class files and allow you to use them in the class paths.

To test this, I created the following class, TempratureConvertorBean.java: /** * TempratureConvertorBean.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */package herong;public class TempratureConvertorBean { private double celsius = 0.0; private double fahrenheit = 32.0; public double getCelsius() { return celsius; } public void setCelsius(double c) { celsius = c; fahrenheit = 1.8*c + 32.0; } public double getFahrenheit() { return fahrenheit; } public void setFahrenheit(double f) { fahrenheit = f; celsius = (f-32.0)/1.8; }

Page 73: Java Tools

public String getInfo() { return new String("My TempraturConvertorBean - Version 1.00"); }}

I did the following to create a JAR file, herong.jar: C:\herong>mkdir cls

C:\herong>javac -d cls TempratureConvertorBean.java

C:\herong>jar cvf herong.jar -C cls herongadded manifestadding: herong/(in = 0) (out= 0)(stored 0%)adding: herong/TempratureConvertorBean.class(in = 798) (out= 458)...

C:\herong>jar tf herong.jarMETA-INF/META-INF/MANIFEST.MFherong/herong/TempratureConvertorBean.class

I also created a testing class, F2C.java: /** * F2C.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */import herong.TempratureConvertorBean;public class F2C { public static void main(String[] arg) { TempratureConvertorBean b = new TempratureConvertorBean(); double f = 0.0; if (arg.length>0) f = Double.parseDouble(arg[0]); b.setFahrenheit(f); double c = b.getCelsius(); System.out.println("Fahrenheit = "+f); System.out.println("Celsius = "+c); System.out.println(b.getInfo()); }}

Here is what I did to test using JAR files in a class path: C:\herong>javac -classpath herong.jar F2C.java

C:\herong>java -cp .;herong.jar F2C 70.0Fahrenheit = 70.0Celsius = 21.11111111111111My TempraturConvertorBean - Version 1.00

This is nice. Right? I can take herong.jar to anywhere on any system. Just add it to "-classpath" for "javac" command, and "-cp" for "java" command.

Creating Executable JAR Files

JAR files can be used to distribute supporting classes. They can also be used to distribute main classes

Page 74: Java Tools

for stand-alone applications.

If you put a stand-alone application into a JAR file, you could make it executable by adding the "Main-Class" attribute to the manifest file.

Here is what I did to add my F2C class to herong.jar and make it executable.

First I created a manifest file, fs_f2c.txt: Main-Class: F2C

Then I added F2C class to herong.jar: C:\herong>javac -classpath herong.jar F2C.java

C:\herong>jar uvmf fs_f2c.txt herong.jar F2C.classupdated manifestadding: F2C.class(in = 919) (out= 551)(deflated 40%)

C:\herong>jar tf herong.jarMETA-INF/META-INF/MANIFEST.MFherong/herong/TempratureConvertorBean.classF2C.class

Now herong.jar contains a small stand-alone application. But how to execute this JAR file? That's easy. You can run a JAR file with the "java -jar" command like this: C:\herong>java -jar herong.jar 60.0Fahrenheit = 60.0Celsius = 15.555555555555555My TempraturConvertorBean - Version 1.00

Cool. Right? But you can make it even better. You can register JAR files to be automatically opened by the "java -jar" command on Windows system to make JAR files "truly" executable. Here is what I did to make this happen.

Warning: this following tutorial modifies Windows registry database. Please do not follow it if you don't have enough knowledge about Windows system.

1. Go to Start > Run. And enter "regedit" followed by clicking OK. Registry Editor window shows up.

2. Go to [HKEY_CLASSES_ROOT\jarfile\shell\open\command]. You should see the current value like this: ("C:\Program Files\Java\j2re1.4.2\bin\javaw.exe" -jar "%1" %*). This was added when you install JDK on your system.

3. Double click this value and change it to: ("C:\Program Files\Java\j2re1.4.2\bin\java.exe" -jar "%1" %*).

4. Open a command window and try this: C:\herong>herong.jar 50

Fahrenheit = 50.0Celsius = 10.0My TempraturConvertorBean - Version 1.00

Page 75: Java Tools

Better. Right? You can run any JAR files by just typing their file names now.

You can also double click any JAR files on Window Explorer now. Try it and see what happens.

Page 76: Java Tools

Chapter - 11'javap' - The Java Class File Disassembler

This chapter provides tutorial notes on 'javap', the Java class file disassember. Topics include list of 'javap' command options, showing public variables and methods, showing private variables and methods, disassembling bytecode to JVM assembler code.

'javap' - Java Disassembler Command and Options

Listing Public Variables and Methods with 'javap'

Listing Private Variables and Methods with 'javap -private'

Disassembling Java Bytecode Class Files with 'javap -c -private'

Looking Up Method Signature with 'javap' Command

'javap' - Java Disassembler Command and Options

"javap": A command line tool that reads Java bytecode class files and disassembles them. "javap" is distributed as part of the Sun JDK package and represented by the \j2sdk1.5.0\bin\javap.exe program file. It has the following syntax: javap [options] classnames

where "options" is a list of options and "classnames" is a list of Java classe names.

If you want to see the complete list of all options, you can run the "javap" command with the "-help" option: C:\herong>javap -help

Usage: javap <options> <classes>...

where options include: -c Disassemble the code -classpath <pathlist> Specify where to find user class files -extdirs <dirs> Override location of installed extensions -help Print this usage message -J<flag> Pass <flag> directly to the runtime system -l Print line number and local variable tables -public Show only public classes and members -protected Show protected/public classes and members -package Show package/protected/public classes and members (default) -private Show all classes and members -s Print internal type signatures -bootclasspath <pathlist> Override location of class files loaded by the bootstrap class loader -verbose Print stack size, number of locals and args for methods. If verifying, print reasons

Listing Public Variables and Methods with 'javap'

In order to test the Java disassembler tool, I wrote this simple Java application file, Circle.java:

Page 77: Java Tools

/** * Circle.java * Copyright (c) 2006 by Dr. Herong Yang, http://www.herongyang.com/ */public class Circle { public String uom = "Centimeter"; private int x = 0; private int y = 0; private int r = 1;

public void setRadius(int radius) { r = radius; } public void setCenter(int centerX, int centerY) { x = centerX; y = centerY; } public void printRadius() { System.out.println(r + " " + uom); } public void printArea() { double area = getArea(); System.out.println(area + " " + uom + "^2"); } private double getArea() { return 3.14159*r*r; }}

To test "javap", we need to compile this source code file into a bytecode class file, Circle.class: C:\herong>javac Circle.java

C:\herong>dir Circle.*

1,153 Circle.class 630 Circle.java

Now we can see what "javap" will do for use on this bytecode class file: C:\herong>javap Circle

Compiled from "Circle.java"public class Circle extends java.lang.Object{ public java.lang.String uom; public Circle(); public void setRadius(int); public void setCenter(int, int); public void printRadius(); public void printArea();}

Very nice. By default, "javap" print a list of all public variables and methods.

Listing Private Variables and Methods with 'javap -private'

From the previous tutorial, we learned that the default behavior of the "javap" command is to list all

Page 78: Java Tools

public variables and methods of the specified class.

If you want to list both public and private variables and methods, you can use the "javap" command with the "-private" option: C:\herong>javap -private Circle

Compiled from "Circle.java"public class Circle extends java.lang.Object{ public java.lang.String uom; private int x; private int y; private int r; public Circle(); public void setRadius(int); public void setCenter(int, int); public void printRadius(); public void printArea(); private double getArea();}

As you can see from the output, all private and public variables and methods are printed by the "javap" command.

Disassembling Java Bytecode Class Files with 'javap -c -private'

Actually, the main function of "javap" is to disassemble Java bytecodes with the "-c" option. The disassembed codes are execution instructions of JVM (Java Virtual Machine).

Now, let's try "javap -c -private" with the bytecode compiled from Circle.java source code. C:\herong>javap -private Circle

Compiled from "Circle.java"public class Circle extends java.lang.Object{public java.lang.String uom;

private int x;

private int y;

private int r;

public Circle(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: aload_0 5: ldc #2; //String Centimeter 7: putfield #3; //Field uom:Ljava/lang/String; 10: aload_0 11: iconst_0 12: putfield #4; //Field x:I 15: aload_0 16: iconst_0 17: putfield #5; //Field y:I 20: aload_0

Page 79: Java Tools

21: iconst_1 22: putfield #6; //Field r:I 25: return

public void setRadius(int); Code: 0: aload_0 1: iload_1 2: putfield #6; //Field r:I 5: return

public void setCenter(int, int); Code: 0: aload_0 1: iload_1 2: putfield #4; //Field x:I 5: aload_0 6: iload_2 7: putfield #5; //Field y:I 10: return

...

private double getArea(); Code: 0: ldc2_w #18; //double 3.14159d 3: aload_0 4: getfield #6; //Field r:I 7: i2d 8: dmul 9: aload_0 10: getfield #6; //Field r:I 13: i2d 14: dmul 15: dreturn

}

Note that:

• I used "-c" and "-private" options together to disassemble both private and public methods. • All class level variables are printed out in the disassembled codes as comments like "//Field r:I". • Constants are printed out in the disasembled codes as comments like "//double 3.14159d". • String constants are also printed out in the disasembled codes as comments like "//String

Centimeter". So don't distribute any Java bytecode compiled from source codes that contain any password strings. People can easy find the passwords using the "javap" tool.

• If you want to understand each statement listed in the disassembled code, you need to read the JVM Specification first.

Looking Up Method Signature with 'javap' Command

"javap" can also be used as a handy tool to look up method signatures while you are writing Java programs.

For example, if you are coding a Java program, and you need to convert a byte array into a character string, but you don't remember which method in the String class to use, and how many arguments are

Page 80: Java Tools

needed for that method. If you are using a good Java IDE, it will help you with a list of public methods and their signatures.

But what can you do, if you are using a simple text editor, not a smart Java IDE? You can use the "javap" command as a handy tool to look up method signatures. The following tutorial example shows you how to find the method to convert a byte array into a character string: C:\herong>javap java.lang.String | find "byte"

public java.lang.String(byte[], int, int, int); public java.lang.String(byte[], int); public java.lang.String(byte[], int, int, java.lang.String) throws java.io.UnsupportedEncodingException; public java.lang.String(byte[], java.lang.String) throws java.io.UnsupportedEncodingException; public java.lang.String(byte[], int, int); public java.lang.String(byte[]); public void getBytes(int, int, byte[], int); public byte[] getBytes(java.lang.String) throws java.io.UnsupportedEncodingException; public byte[] getBytes();

What can you learn from this tutorial example:

• "java.lang.String" is the fully qualified class name for the String class. • The bytecode of "java.lang.String" is inside the JDK JAR file: \j2sdk1.5.0\jre\lib\rt.jar. since

"rt.jar" is the default JAR file, you don't need to specify it with the "-classpath" option. • I used the Windows "find" command (similar to the Unix "grep" command) to select method

signatures that contains the word "byte" to reduce the amount of output lines. • Based on the output, the simplest method is the constructor "String(byte[])", which converts all

bytes in the specified byte array into a string using the default character encoding.

Page 81: Java Tools

Chapter - 12'keytool' - Public Key Certificate Tool

This chapter provides notes and tutorials on the public key certificate management tool, 'keytool'. Topics include introduction of certificates and 'keystore' files, list of 'keytool' commands, generating private and public key pair, importing and exporting certificates.

Certificates and Certificate Chains

'keystore' - Public Key Certificate Storage File

JDK 1.5 'keytool' - keystore File Management Commands

JDK 1.6 'keytool' - keystore File Management Commands

Generating Key Pairs and Self-Signed Certificates

Exporting and Import Certificates

Cloning Certificates with New Identities

Conclusion:

• A key entry in keystore contains a private key and a certificate of the public key. • Certificates can be exported into certificate files out of keystore. • Certificates can be imported from certificate back into keystore. • There seems be to no way to export private keys. • There seems be to no way to generate a certificate of a given public key - signing a public key.

Certificates and Certificate Chains

Certificate: A digitally signed statement from the issuer saying that the public key of the subject has some specific value.

The above definition is copied from the JDK 1.3.1 documentation. It has a couple of important terms:

• "signed statement" - The certificate must be signed by the issuer with a digital signature. • "issuer" - The person or organization who is issuing this certificate. • "public key" - The public key of a key pair selected by the subject. • "subject" - The person or organization who owns the public key.

X.509 Certificate - A certificate written in X.509 standard format. X.509 standard was introduction in 1988. It requires a certificate to have the following information:

• Version - X.509 standard version number. • Serial Number - A sequence number given to each certificate. • Signature Algorithm Identifier - Name of the algorithm used to sign this certificate by the issuer • Issuer Name - Name of the issuer. • Validity Period - Period during which this certificate is valid. • Subject Name - Name of the owner of the public key. • Subject Public Key Information - The public key and its related information.

How can you get a certificate for your own public key?

• Requesting it from a Certificate Authority (CA), like VeriSign, Thawte or Entrust.

Page 82: Java Tools

• Doing it yourself - using tools like JDK "keytool" to generate a self-signed certificate.

Certificate Chain: A series of certificates that one certificate signs the public key of the issuer of the next certificate. Usually the top certificate (the first certificate) is self-signed, where issuer signed its own public key.

'keystore' - Public Key Certificate Storage File

"keystore" - A database used by JDK "keytool" command and KeyStore class to store your own private keys, and public key certificates you received from someone else. "keystore" supports the following features:

• Two types of entries: key entries for private keys and certificate entries for public key certificates.

• A key entry contains the private key and a certificate chain of the corresponding public key. • Every entry has a unique alias name. • Key entries are protected by separate passwords. • "keystore" may have different implementations from different security package providers. The

default implementation from Sun is called JKS (Java KeyStore).

JDK 1.5 'keytool' - keystore File Management Commands

"keytool" is command line tool introduced in JDK 1.2 to manage keys and certificates using "keystore". "keytool" replaces the same functions offered by "javakey" in JDK 1.1. "keytool" offers a number functions through the following major command options:

• "-certreq": Generates a Certificate Signing Request (CSR). • "-delete": Deletes the entry of the specified alias name. • "-export": Exports the certificate of the specified key entry or certificate entry out of the

keystore to a certificate file. • "-genkey": Generates a key pair and stores it as a key entry in the keystore. • "-help": Lists the basic commands and their options. • "-identitydb": Reads the JDK 1.1.x-style identity database from the file idb_file, and adds its

entries to the keystore. If no file is given, the identity database is read from stdin. If a keystore does not exist, it is created.

• "-import": Imports the certificate from a certificate file as a certificate entry into the keystore. • "-keyclone": Creates a new key entry by copying an existing key entry. • "-keypasswd": Changes the password under which the private/secret key identified by alias is

protected, from old_keypass to new_keypass, which must be at least 6 characters long. • "-list": Lists all entries in the keystore. • "-printcert": Prints summary information of a certificate from a certificate file. • "-selfcert": Replaces the certificate in a key entry with a new self-signed certificate. • "-storepasswd": Changes the password used to protect the integrity of the keystore contents. The

new password is new_storepass, which must be at least 6 characters long..

The above list of "keytool" commands are supported by JDK 1.5. See next section for "keytool"

Page 83: Java Tools

commands supported in JDK 1.6.

JDK 1.6 'keytool' - keystore File Management Commands

In JDK 1.6, the "keytool" has been changed to offer the following set of commands:

• "-genkeypair": Same as the old command "-genkey" to generate a key pair (a public key and associated private key). Wraps the public key into an X.509 v3 self-signed certificate, which is stored as a single-element certificate chain. This certificate chain and the private key are stored in a new keystore entry identified by alias.

• "-genseckey": Generates a secret key and stores it in a new KeyStore.SecretKeyEntry identified by alias.

• "-importcert": Same as the old commnad "-import" to read the certificate or certificate chain (where the latter is supplied in a PKCS#7 formatted reply) from the file cert_file, and stores it in the keystore entry identified by alias. If no file is given, the certificate or PKCS#7 reply is read from stdin.

• "-importkeystore": Imports a single entry or all entries from a source keystore to a destination keystore. The "-importkeystore" command can also be used to migrate keys from other storage formats like PKCS#12.

• "-certreq": Generates a Certificate Signing Request (CSR), using the PKCS#10 format. • "-exportcert": Same as the old commnad "-export" to read (from the keystore) the certificate

associated with alias, and stores it in the file cert_file. • "-list": Prints (to stdout) the contents of the keystore entry identified by alias. If no alias is

specified, the contents of the entire keystore are printed. • "-printcert": Reads the certificate from the file cert_file, and prints its contents in a human-

readable format. If no file is given, the certificate is read from stdin. • "-storepasswd": Changes the password used to protect the integrity of the keystore contents. The

new password is new_storepass, which must be at least 6 characters long.. • "-keypasswd": Changes the password under which the private/secret key identified by alias is

protected, from old_keypass to new_keypass, which must be at least 6 characters long. • "-delete": Deletes from the keystore the entry identified by alias. The user is prompted for the

alias, if no alias is provided at the command line. • "-changealias": Move an existing keystore entry from the specified alias to a new alias,

destalias. If no destination alias is provided, the command will prompt for one. If the original entry is protected with an entry password, the password can be supplied via the "-keypass" option. If no key password is provided, the storepass (if given) will be attempted first. If that attempt fails, the user will be prompted for a password.

• "-help": Lists the basic commands and their options.

Generating Key Pairs and Self-Signed Certificates

In the first example, I want to try the "-genkey" command option using JDK 1.3.1: C:\herong>keytool -genkey -alias my_home -keystore herong.jks

Enter keystore password: HerongJKSWhat is your first and last name? [Unknown]: Herong YangWhat is the name of your organizational unit?

Page 84: Java Tools

[Unknown]: My UnitWhat is the name of your organization? [Unknown]: My HomeWhat is the name of your City or Locality? [Unknown]: My CityWhat is the name of your State or Province? [Unknown]: My StateWhat is the two-letter country code for this unit? [Unknown]: USIs <CN=Herong Yang, OU=My Unit, O=My Home, L=My City, ST=My State, C=US> correct? [no]: yesEnter key password for <my_home> (RETURN if same as keystore password): My1stKey

Based on the documentation, the above example command should do the following for me:

• Create a "keystore" file, herong.jks, in JKS format, with password of "HerongJKS". • Generate a pair of private key and public key for me using the default implementation of the

default security package. • Generate a certificate chain with a single self-signed certificate of my public key. • Insert a key entry into the keystore with my private key and the certificate chain.

The following command shows that we do have a key entry in the keystore file: C:\herong>keytool -list -keystore herong.jks -storepass HerongJKS

Keystore type: jksKeystore provider: SUN

Your keystore contains 1 entry:

my_home, Sat Jun 1 07:15:16 EDT 2002, keyEntry,Certificate fingerprint (MD5): BE:D2:AF:4E:A7:44:13:08:16:4C:68:3B:D1:99:79:55

Exporting and Import Certificates

In the second example, I want to export the certificate stored in the key entry to a certificate file, then import it back into the keystore as certificate entry: C:\herong>keytool -export -alias my_home -file my_home.crt -keystore herong.jks -storepass HerongJKS

Certificate stored in file <my_home.crt>

C:\herong>keytool -printcert -file my_home.crt

Owner: CN=Herong Yang, OU=My Unit, O=My Home, L=My City, ST=My Sta...Issuer: CN=Herong Yang, OU=My Unit, O=My Home, L=My City, ST=My St...Serial number: 407928a4Valid from: Sat Jun 1 07:14:44 EDT 2002 until: Sat Aug 31 07:14:44...Certificate fingerprints: MD5: BE:D2:AF:4E:A7:44:13:08:16:4C:68:3B:D1:99:79:55 SHA1: AE:67:0C:C5:21:5C:F6:6F:45:33:9E:FB:8E:50:EA:32:32:D1:92:BB

C:\herong>keytool -import -alias my_home_crt -file my_home.crt -keystore herong.jks -storepass HerongJKS

Page 85: Java Tools

Certificate already exists in keystore under alias <my_home>Do you still want to add it? [no]: yesCertificate was added to keystore

C:\herong>keytool -list -keystore herong.jks -storepass HerongJKS

Keystore type: jksKeystore provider: SUN

Your keystore contains 2 entries:

my_home_crt, Sat Jun 1 12:25:46 EDT 2004, trustedCertEntry,Certificate fingerprint (MD5): BE:D2:AF:4E:A7:44:13:08:16:4C:68:3B...my_home, Sat Jun 1 07:15:16 EDT 2002, keyEntry,Certificate fingerprint (MD5): BE:D2:AF:4E:A7:44:13:08:16:4C:68:3B...

Looking good so far:

• The "-export" command option exports the self-signed certificate of my public key into a file, my_home.crt.

• The "-printcert" command option prints out summary information of a certificate stored in a file in X.509 format. As you can see from the print out, I am the issuer and the owner of this certificate.

• The "-import" command option imports the certificate from the certificate file back into the keystore under different alias, my_home_crt.

Certificates can also be exported in a printable format: based on RFC 1421 specification, using the BASE64 encoding algorithm. C:\herong>keytool -export -alias my_home_crt -file my_home.rfc -rfc -keystore herong.jks -storepass HerongJKS

Certificate stored in file <my_home.rfc>

type my_home.rfc-----BEGIN CERTIFICATE-----MIIDDTCCAssCBEB5KKQwCwYHKoZIzjgEAwUAMGwxCzAJBgNVBAYTAlVTMREwDwYDVQ...dGF0ZTEQMA4GA1UEBxMHTXkgQ2l0eTEQMA4GA1UEChMHTXkgSG9tZTEQMA4GA1UECx...dDEUMBIGA1UEAxMLSGVyb25nIFlhbmcwHhcNMDQwNDExMTExNDQ0WhcNMDQwNzEwMT...MQswCQYDVQQGEwJVUzERMA8GA1UECBMITXkgU3RhdGUxEDAOBgNVBAcTB015IENpdH...BAoTB015IEhvbWUxEDAOBgNVBAsTB015IFVuaXQxFDASBgNVBAMTC0hlcm9uZyBZYW...ASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2US...WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1...+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCou...gYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgL...FhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkI...BpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAJdQsMlIf1nh4T/HZvVeltsrTGED118CkG...ygy53OLwrSK+6ptJpXP8tPMn9YFVJ3eigJrMTaZvGyd40WRiYM6Woyj3T4H73LEKLD...QeNYOAm8cp3l9ZQkNnmIA1P6CRR43EeAmdTUlK8y6RWTsrOiJMdDMAsGByqGSM44BA...AhQ4zAUOPWe1wdiwye9XDsVPcKS1xwIUWTdok6RIeeCMRIytKwcTOo7/qpM=-----END CERTIFICATE-----

Cloning Certificates with New Identities

In the third example, I want to create a new key entry with the same key pair of an existing key entry,

Page 86: Java Tools

but change the identity information: C:\herong>keytool -keyclone -alias my_home -dest my_copy -keypass My1stKey -new My2ndKey -keystore herong.jks -storepass HerongJKS

C:\herong>keytool -selfcert -alias my_copy -keypass My2ndKey -dname "cn=Herong Yang, ou=My Unit 2, o=My Organization 2, c=US" -keystore herong.jks -storepass HerongJKS

C:\herong>keytool -export -alias my_copy -file my_copy.crt -keystore herong.jks -storepass HerongJKS Certificate stored in file <my_copy.crt>

C:\herong>keytool -printcert -file my_copy.crt

Owner: CN=Herong Yang, OU=My Unit 2, O=My Organization 2, C=USIssuer: CN=Herong Yang, OU=My Unit 2, O=My Organization 2, C=USSerial number: 40798b4fValid from: Sat Jun 1 14:15:43 EDT 2002 until: Sat Aug 31 14:15:43...Certificate fingerprints: MD5: 4A:E4:D9:BC:E9:8C:50:27:6C:00:59:76:D1:14:05:79 SHA1: FA:F5:30:78:22:3B:52:28:0D:41:24:0B:CA:CC:6F:D4:0E:...

Page 87: Java Tools

Chapter -12native2ascii' - Native-to-ASCII Encoding Converter '

This chapter provides tutorial notes on the native-to-ASCII encoding converter 'native2ascii'. Topics include 'native2ascii' command options, default encoding CP1252 used by 'javac', converting UTF-8 characters into \udddd Unicode code sequences, converting \udddd sequences back to native encodings.

'native2ascii' - Encoding Converter Command and Options

'javac' Using CP1252 to Process Source File

UTF-8 to \udddd Conversion with 'native2ascii -encoding'

Setting UTF-8 Encoding in PrintStream

Converting \udddd Sequences Back with "-reverse" Option

'native2ascii' - Encoding Converter Command and Options

"native2ascii": A command line tool that reads a text file stored in a non-ASCII encoding and converts it to an ASCII text file. All non-ASCII characters will be converted into \udddd sequences, where dddd is the Unicode code value of the non-ASCII character.

"native2ascii" is an important Java tool, because Java compiler and other Java tools can only process files which contain ASCII characters and \udddd Unicode code sequences. If you have any non-ASCII character strings written in a native encoding included in your Java source code, you need to run this "native2ascii" tool to convert your Java source code.

"native2ascii" has the following command syntax: native2ascii [options] inputfile outputfile

where "options" is a list of these options:

• "-encoding encoding_name" - Specify the encoding name which is used by the conversion procedure. The "encoding_name" string must be one of those supported encodings in the Supported Encodings document. "encoding_name" example: utf-8.

• "-reverse" - Perform the reverse operation: convert a file with \udddd Unicode code sequences to one with native-encoded characters.

'javac' Using CP1252 to Process Source File

In order to test the "native2ascii" tool, I wrote the following Java source code file: HelloUtf8.java public class HelloUtf8 { public static void main(String[] a) { System.out.println("Hello world!"); System.out.println("世界你好!"); }}

"HelloUtf8.java" contains a string of Chinese characters written in UTF-8 encoding. When I tried to

Page 88: Java Tools

compile it, I got the following warning: C:\herong>javac HelloUtf8.java

HelloUTF8.java:4: warning: unmappable character for encoding Cp1252 System.out.println("S+ t S+ s +n+?");� �� � � ^1 warning

The compiler used "Cp1252" as the default encoding to process the source file, HelloUtf8.java. The last character of my Chinese string encoded in UTF-8 can not be mapped to any CP1252 character. But the compiler did finish the compilation. The output HelloUtf8.class can still be executed in JVM: C:\herong>java HelloUtf8

Hello world!S+ t S+ s +n+?� �� � �

But the last character was compiled as a question mark "?" character. To fix this problem, you need to use the "native2ascii" tool - see the next section.

UTF-8 to \udddd Conversion with 'native2ascii -encoding'

Now let's see how we can fix the encoding problem with HelloUtf8.java demonstrated in the previous section.

1. Convert HelloUtf8.java to \udddd Unicode code sequences using the "native2ascii -encoding utf-8" command: C:\herong>native2ascii -encoding utf-8 HelloUtf8.java HelloUtf8Converted.java

2. Rename the class name in HelloUtf8Converted.java with an editor: public class HelloUtf8Converted { public static void main(String[] a) { System.out.println("Hello world!"); System.out.println("\u4e16\u754c\u4f60\u597d\uff01"); }}

3. Compile and run HelloUtf8Converted.java: C:\herong>javac HelloUtf8Converted.java

C:\herong>java HelloUtf8Converted

Hello world!?????

What happens to the Chinese string printed on the console? Why I am not getting Chinese characters back in the output?

The problem is not caused by those \udddd Unicode code sequences used to represent the Chinese string. Those \udddd Unicode code sequences correctly inserted Chinese characters into the storage of a string variable. The problem is caused by the default encoding used by the "out" stream. See the next

Page 89: Java Tools

section on how to fix this problem.

Setting UTF-8 Encoding in PrintStream

In order to print non-ASCII characters stored in Java strings, you need to set the correct encoding in the PrintStream object.

Here is how I fixed the problem you saw in the previous section: import java.io.*;public class HelloUtf8ConvertedFixed { public static void main(String[] a) { try { PrintStream out = new PrintStream("\\herong\\Hello.txt", "UTF-8"); System.setOut(out); System.out.println("Hello world!"); System.out.println("\u4e16\u754c\u4f60\u597d\uff01"); } catch (Exception e) { } }}

Check the output of this program: C:\herong>javac HelloUtf8ConvertedFixed.java

C:\herong>java HelloUtf8ConvertedFixed

C:\herong>type Hello.txt

Hello world!世界你好!

Excellent! This final program shows how Chinese characters can be correctly encoded in the Java source file, and correctly printed in the output file.

Converting \udddd Sequences Back with "-reverse" Option

"native2ascii" also offers the "-reverse" option to help you convert text files with any \udddd Unicode code sequences back to any native encodings, like UTF-8, or GB2312.

The tutorial example below shows you how I converted some Chinese characters in a UTF-8 file to \udddd Unicode code sequences, then back to a GB2312 encoded file: C:\herong>type HelloUtf8.javapublic class HelloUtf8 { public static void main(String[] a) { System.out.println("Hello world!"); System.out.println("世界你好!"); }}

C:\herong>native2ascii -encoding utf-8 HelloUtf8.java HelloUtf8.unicode

Page 90: Java Tools

C:\herong>type HelloUtf8.unicodepublic class HelloUtf8 { public static void main(String[] a) { System.out.println("Hello world!"); System.out.println("\u4e16\u754c\u4f60\u597d\uff01"); }}

C:\herong>native2ascii -encoding gb2312 -reverse HelloUtf8.unicode HelloUtf8.gb2312

C:\herong>type HelloUtf8.gb2312public class HelloUtf8 { public static void main(String[] a) { System.out.println("Hello world!"); System.out.println("-++t-p¦+úí"); }}

As you can see, if you use "native2ascii" and "native2ascii -reverse" together, you can convert any non-ASCII file from one encoding to another encoding.

Monitor and diagnose performance in Java SE 6

Summary: Java™ Platform, Standard Edition 6 (Java SE) focuses on performance, with expanded tools for managing and monitoring applications as well as diagnosing common problems. This article outlines the basis of monitoring and management in the Java SE platform and provides detailed information about the relevant enhancements in Java SE 6.

Java SE 6 provides an in-depth focus on performance, offering expanded tools for managing and monitoring applications and for diagnosing common problems. The improvements include:

• Monitoring and management API enhancements • Official support for an improved graphical monitoring tool called JConsole • Enhanced instrumentation of the Java virtual machine (JVM)

This article outlines the basis of monitoring and management in the Java SE platform and provides detailed information about the performance monitoring and management enhancements in the latest release. It also describes the diagnostic and troubleshooting tools available in the Java SE 6 platform.

To benefit from this article, you should have a strong understanding of the monitoring and management functionality introduced in previous Java SE releases. See Resources for detailed background information.

Monitoring and management API

The java.lang.management package introduced in Java SE 5 defines nine MBeans called platform MBeans, or MXBeans (see Resources). Each MXBean encapsulates a single functional area of the JVM. Beginning with Java SE 5, the JVM has included a built-in MBean server called the platform

Page 91: Java Tools

MBean server. MBeans reside in and are managed by this repository. Table 1 outlines the nine MXBeans in the Java platform:

Table 1. Platform MBeansManagement interface Resource managed

ClassLoadingMXBean Class loaderCompilationMXBean CompilerMemoryMXBean MemoryThreadMXBean ThreadsRuntimeMXBean RuntimeOperatingSystemMXBean Operating systemGarbageCollectorMXBean Garbage collectorMemoryManagerMXBean Memory managerMemoryPoolMXBean Memory poolAny application can obtain and use the JVM-provided platform MBeans by obtaining an instance of the desired bean and invoking the appropriate methods. MXBeans can be used to monitor the behavior of both local and remote JVMs and retrieve information about them.

Platform MBeans provide access to information such as the number of classes loaded, uptime of the JVM, the amount of memory consumed, and the number of threads running, as well as statistics about thread contention.

You can monitor and manage the JVM resources in one of two ways:

• Direct access to the MXBean interface • Indirect access using the MBeanServer interface

Direct access using the MXBean interface

You can retrieve an MXBean instance from a static factory method that gives you direct access to the locally running JVM's MXBean interface. The ManagementFactory class provides the static factory methods for obtaining the MXBeans. The example in Listing 1 demonstrates how to retrieve the RuntimeMXBean using this factory and get the value of one of its standard attributes: VmVendor:

Listing 1. Direct access to MXBean RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();

// Get the standard attribute "VmVendor"String vendor = mxbean.getVmVendor();

Indirect access using the MBeanServer interface

The platform MBeanServer interface uses MXBeanServerConnection to allow you to connect to remote JVMs and access MXBeans running on those platforms. You can use the ManagementFactory class's getPlatformMBeanServer method to access the platform MBean server. Listing 2 demonstrates how to get the RuntimeMXBean running in a remote JVM and get the value of its VmVendor attribute:

Page 92: Java Tools

Listing 2. Indirect access to MXBean MBeanServerConnection serverConn;

try { //connect to a remote VM using JMX RMI JMXServiceURL url = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://<addr>");

JMXConnector jmxConnector = JMXConnectorFactory.connect(url);

serverConn = jmxConnector.getMBeanServerConnection();

ObjectName objName = new ObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME);

// Get standard attribute "VmVendor" String vendor = (String) serverConn.getAttribute(objName, "VmVendor");

} catch (...) { }

See Resources for more detailed information on MXBeans and the java.lang.management API.

API enhancements in Java SE 6

Java SE 5 introduced the java.util.concurrent.locks package, which provides a framework for lock and wait conditions. This framework is distinct from Java's built-in synchronization support and allows greater flexibility in the use of locks.

Java SE 6 adds support for java.util.concurrent.locks in the java.lang.management package. This includes new classes that provide information about locks, as well as enhancements to the ThreadInfo, ThreadMXBean, and OperatingSystemMXBean interfaces.

Java SE 6 introduces two new classes:

• LockInfo contains information about a lock. • MonitorInfo extends LockInfo and contains information about an object-monitor lock.

The ThreadInfo class makes use of these new objects with the introduction of three new methods:

• getLockInfo() returns the LockInfo object for which the given thread is blocked waiting.

• getLockedMonitors() returns the MonitorInfo objects that are currently locked by the given thread.

• getLockedSynchronizers() returns the LockInfo objects, representing ownable synchronizers that are currently locked by the given thread.

In Java SE 5, the ThreadMXBean.getThreadInfo methods report only an object monitor that a thread is waiting to acquire or is blocked from entering. In Java SE 6, these methods are enhanced to report the AbstractOwnableSynchronizer that a thread is waiting to acquire.

Four new methods have been added to the ThreadMXBean interface:

• isObjectMonitorUsageSupported() tests if the virtual machine supports monitoring

Page 93: Java Tools

the usage of object monitors.

• isSynchronizerUsageSupported() tests if the virtual machine supports monitoring the usage of ownable synchronizers.

• findDeadlockedThreads() returns an array of thread IDs that are deadlocked. Threads that are deadlocked are blocking one another from entering an object monitor or synchronizer.

• dumpAllThreads() returns stack-trace and synchronization information for all live threads.

Finally, the OperatingSystemMXBean interface was updated to include the getSystemLoadAverage() method, which returns the system load average for the past minute.

In addition to this programmatic support, Java SE 6 also includes several diagnostic and troubleshooting tools that can be used to detect problems and monitor usage of JVM resources. The next two sections describe and demonstrate some of the available diagnostic tools.

Java Monitoring and Management Console (JConsole)

Java SE 6 includes official support for JConsole, a monitoring and management console introduced in Java SE 5. JConsole lets you monitor various JVM resource statistics during run time. It's particularly useful for detecting symptoms of deadlocks, lock contention, memory leaks, and cycling threads. It can connect to a local or remote JVM and can be used to monitor:

• Thread state (including associated locks) • Memory usage • Garbage collection • Runtime information • JVM information

The following subsections describe the enhancements made to JConsole in Java SE 6. See Resources for more information on how to start and use JConsole.

Attach API support

Beginning in Java SE 6, JConsole implements the new Attach API. This API consists of two packages — com.sun.tools.attach and com.sun.tools.attach.spi — that let implementing applications dynamically attach to a target virtual machine and run their agents within that JVM.

In the past, applications that you wanted to monitor with JConsole needed to be started with the -Dcom.sun.management.jmxremote option; applications no longer need to start with this option. Support for dynamic attachment makes JConsole capable of monitoring any application that supports the Attach API. Compliant applications are automatically detected when JConsole starts up.

Enhanced UI and MBean presentation

In Java SE 6, JConsole has been updated to have a look and feel similar to the Windows® operating system or GNOME desktop, depending on which platform it's running on. The screenshots shown throughout the rest of this article were taken on Windows XP and show the UI features that have changed from the previous release.

Once started and associated with an application, the JConsole view consists of six tabs, each representing a different JVM resource or set of resources:

• Overview • Memory

Page 94: Java Tools

• Threads • Classes • VM Summary • MBeans

The Overview tab displays correlated information about memory usage, threads, classes, and CPU usage in a graphical format. The Overview tab displays a set of related information on one page that was available previously only by switching among multiple tabs. Figure 1 shows the Overview tab for a sample application:

Figure 1. JConsole Overview tab

Page 95: Java Tools
Page 96: Java Tools

The Overview tab displays four graphs of VM resource-usage information as well as a pick list for altering the time range for which you would like to see results. The first graph, Heap Memory Usage, displays the amount of heap memory that has been used in megabytes over time. This graph is useful in detecting memory leaks. If a memory leak is present in your application, the heap memory usage steadily increases over time.

The Threads graph plots the number of live threads over time, and the Classes graph depicts the number of classes loaded. The CPU Usage chart depicts the percentage of the CPU your application uses at various points in its life cycle.

The VM Summary tab, shown in Figure 2, is another new addition to the Java SE 6 release. It provides detailed information about the JVM, including total uptime, threading information, classes loaded, memory statistics, garbage collection, and operating-system information.

Figure 2. JConsole VM Summary tab

Page 97: Java Tools
Page 98: Java Tools

The MBeans tab has been improved to allow for easier access to your MBeans' operations and attributes. It displays information about all MBeans registered with the platform. All platform MBeans are accessible through this tab. The tree structure along the left-hand side displays all currently running MBeans. When you select an MBean, its MBeanInfo and descriptor are displayed on the table to the right, as shown in Figure 3:

Figure 3. JConsole MBean tab

Selecting the Attributes node displays all the MBean's attributes, as shown in Figure 4 for the Threading MBean:

Figure 4. MBean attributes

Page 99: Java Tools

Note that the attributes and their values shown in the box to the right map to the attribute values attainable through the ThreadMXBean API in the java.lang.management package previously described. You can obtain additional information about a listed attribute by double-clicking on the attribute value. Only attribute values shown in bold can be expanded. For example, double-clicking on the AllThreadIds value displays the thread IDs of all 22 threads, as shown in Figure 5:

Figure 5. Expanded attribute value

Page 100: Java Tools

Writeable attributes are displayed in blue and you can edit them by clicking on them and entering the new value. For example, the ThreadContentionMonitoringAvailable attribute shown in Figure 5 can be edited in this manner from the JConsole view.

Selecting the Operations node in the left-hand tree structure displays the operations associated with that MBean. The MBean operations appear as buttons in the right-side display and, when clicked on, invoke the specified method. Figure 6 shows the operations available for ThreadMXBean:

Figure 6. MBean operations

Page 101: Java Tools

The HotSpot Diagnostic MBean

In Java SE 6, JConsole includes support for the HotSpot Diagnostic MBean. This MBean was introduced in this release to allow you to perform on-the-spot diagnostic operations. Its API lets users perform a heap dump and set other VM options during run time. You can access the HotSpot Diagnostic MBean from the MBean tab by expanding the com.sun.management node and selecting HotSpotDiagnostic. Methods available from the HotSpot Diagnostic MBean are shown in Figure 7:

Figure 7. HotSpot Diagnostic MBean

Page 102: Java Tools

JConsole plug-in support

Beginning in Java SE 6, JConsole includes plug-in support that allows you to build your own plug-ins to run with JConsole. For example, you can add a custom tab to the JConsole main view for accessing application-specific MBeans and for performing your own monitoring activities.

You must extend the abstract com.sun.tools.jconsole.JConsolePlugin class to create a custom JConsole plug-in. You implement two methods for a plug-in to appear properly in the JConsole view:

• newSwingWorker() returns a SwingWorker object that performs the GUI updates for your plug-in.

• getTabs() returns a map of tabs to be added to the JConsole window.

JConsole uses its service-provider mechanism to detect and load all plug-in classes. For this reason, you must provide your plug-in class in a JAR file containing a file named META-INF/services/com.sun.tools.jconsole.JConsolePlugin. This file should contain a list of the fully qualified plug-in class names, one per line. To load the new plug-ins into the JConsole view, run JConsole from the command line with the command:jconsole -pluginpath plugin_path

In this command, plugin_path refers to the paths to the directory or archive of JConsole plug-ins. You

Page 103: Java Tools

can specify multiple paths.

Java SE 6 comes equipped with a sample JConsole plug-in called JTop. JTop shows the CPU usage of the threads running within the current application. To run JConsole with the JTop, execute the command:jconsole -pluginpath JAVA_HOME/demo/management/JTop/JTop.jar

Figure 8 shows an instance on JConsole with the JTop tab selected. The left-hand column displays the names of all running threads. For each thread, the CPU usage and thread state are displayed. This view refreshes automatically as statistics change. The JTop plug-in is useful for identifying threads with high CPU consumption.

Figure 8. JConsole JTop plug-in

Back to top

Monitoring and troubleshooting tools

In addition to JConsole, Java SE 6 includes support for a number of other command-line tools. These diagnostic tools can attach to any application without requiring that application to start in a special mode. They enable you to obtain more information about an application to determine if it is behaving as you expect. Note that these tools are listed as experimental and might not be fully supported in future Java SE releases.

Monitoring tools

Java SE 6 includes three command-line utilities, listed in Table 2, that are useful for monitoring JVM performance statistics:

Page 104: Java Tools

Table 2. Monitoring toolsTool Description

jps JVM process status tooljstat JVM statistics monitoring tooljstatd JVM jstat daemonThe jps utility lists the virtual machines for the current user on the target system. The utility is useful in environments where the VM is started using the JNI Invocation API rather than the standard Java launcher. In these environments, it is not always easy to recognize the Java processes in the process list. The jps tool alleviates this problem.

The following example demonstrates the use of the jps utility. Simply enter jps on the command line, and the utility lists the virtual machines and process IDs for which the user has access rights, as shown in the example in Listing 3:

Listing 3. Using the jps utility $ jps16217 MyApplication16342 jps

The jstat utility uses the JVM's built-in instrumentation to provide information on performance and resource consumption of running applications. The tool is useful for diagnosing performance issues, particularly issues related to heap sizing and garbage collection.

The jstatd daemon is a Remote Method Invocation (RMI) server application that monitors the creation and termination of JVMs and provides an interface to allow remote monitoring tools to attach to JVMs running on the local host. For example, this daemon allows the jps utility to list processes on a remote system.

See Resources for additional documentation and usage examples for each of these tools.

Troubleshooting tools

Java SE 6 also includes a number of troubleshooting tools, listed in Table 3, that can help you pinpoint portions of your application that are behaving unexpectedly:

Table 3. Troubleshooting toolsTool Description

jinfo Configuration informationjhat Heap dump browserjmap Memory mapjsadebugd Serviceability agent debug daemonjstack Stack traceThe jinfo command-line utility retrieves configuration information from a running Java process or crash dump and prints the system properties or the command-line flags that were used to start the virtual machine.

The jhat tool provides a convenient means to browse the object topology in a heap snapshot. This tool, introduced in Java SE 6 release to replace the Heap Analysis Tool (HAT), is useful in detecting

Page 105: Java Tools

memory leaks.

The jmap command-line utility prints memory-related statistics for a running VM or core file. The utility can also use the jsadebugd daemon to query a process or core file on a remote machine. The jmap tool is useful in diagnosing excessive use of finalizers, which can result in an OutOfMemoryError.

The Serviceability Agent Debug Daemon (jsadebugd) attaches to a Java process or to a core file and acts as a debug server. This utility is currently available only on Solaris OS and Linux®. Remote clients such as jstack, jmap, and jinfo can attach to this server using Java RMI.

The jstack command-line utility attaches to the specified process or core file and prints the stack traces of all threads that are attached to the virtual machine, including Java threads and VM internal threads, and optionally native stack frames. The utility also performs deadlock detection. It can use the jsadebugd daemon to query a process or core file on a remote machine. The jstack tool is useful for diagnosing deadlocks.

See Resources for additional documentation and usage examples for each of these tools.

Back to top

Conclusion

The Java 6 platform delivers several enhancements in VM instrumentation, management APIs, and JDK tools to help you efficiently identify and diagnose performance and memory problems within Java applications. This article describes the improvements made to the Java SE monitoring and managing framework and touches on the diagnostic command-line utilities available to developers.

Average Java application speed has steadily increased over time. Now, with the Java SE 6 release, Java performance is comparable to that of C or C++. In many cases, Java code runs significantly faster. And you can use the tools described here to achieve better performance optimization. Give them a try. We guarantee you'll find places to optimize your application where you never knew you could.