Java Tools

Share Embed Donate


Short Description

Download Java Tools...

Description

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.

"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.

Chapter - 2 Installing 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 -version java 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

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 Hello Hello world!

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

Chapter - 3 Installing 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 \herong C:\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!

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

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



"-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 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 Specify where to find user class files -cp Specify where to find user class files -sourcepath Specify where to find input source files -bootclasspath Override location of bootstrap class files -extdirs Override location of installed extensions -endorseddirs Override location of endorsed standards path -d Specify where to place generated class files -encoding Specify character encoding used by source files -source Provide source compatibility with specified release -target 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 Pass 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

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 symbol symbol : class Echoer location: 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);

char[] a = r.toCharArray(); int n = a.length; for (int i=0; ijavac 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.class C:\herong>del EchoerTest.class C:\herong>javac -verbose -sourcepath . 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.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

C:\herong>javac PackagedHello.java C:\herong>dir PackagedHell.* 459 PackagedHello.class 264 PackagedHello.java C:\herong>java -cp . PackagedHello Exception 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 .\com C:\herong>mkdir .\com\herong C:\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.PackagedHello Packaged: 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 .\cls C:\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.PackagedHello Packaged: 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

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(); } }

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 .\com C:\herong>mkdir .\com\herong C:\herong>mkdir .\com\herong\util C:\herong>copy ClsA.java .\com\herong\util C:\herong>copy ClsB.java .\com\herong\util C:\herong>javac ImportTestA.java ImportTestA.java:8: cannot access ClsA bad class file: .\ClsA.java file does not contain class ClsA Please remove or make sure it appears in the correct subdirectory of the 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 ClsA bad class file: .\ClsA.java file does not contain class ClsA Please remove or make sure it appears in the correct subdirectory of the 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]

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 1 2 3 4 5 6

Option -g:none -g:lines -g:lines,source (default) -g:lines,source,vars -g

Information generated in class No debug information Line number only Line number & source file Same as #3 Line number, source file & variables 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.

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.



"-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] (to execute a or java [-options] (to execute a

class [args...] class) -jar jarfile [args...] 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 The default VM is client.

[deprecated]

-cp -classpath A ; separated list of directories, JAR archives, and ZIP archives to search for class files. -D= set a system property -verbose[:class|gc|jni] enable verbose output -version print product version and exit -version: 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[:...|:] -enableassertions[:...|:] enable assertions -da[:...|:] -disableassertions[:...|:] disable assertions -esa | -enablesystemassertions enable system assertions -dsa | -disablesystemassertions disable system assertions -agentlib:[=] load native agent library , e.g. -agentlib:hprof see also, -agentlib:jdwp=help and -agentlib:hprof=help -agentpath:[=] load native agent library by full pathname -javaagent:[=] 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:

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 Hello Hello 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; imkdir echo C:\herong>copy Echoer.java echo C:\herong>mkdir test C:\herong>copy EchoerTest.java test C:\herong>cd test C:\herong>javac -classpath ..\echo EchoerTest.java >java EchoerTest Exception in thread "main" java.lang.NoClassDefFoundError: Echoer at EchoerTest.main(EchoerTest.java:7) C:\herong>java -classpath ..\echo EchoerTest Exception 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:

C:\herong>javac Hello.java C:\herong>jar -cvmf hello.fs hello.jar Hello.class added manifest adding: 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.jar Hello 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: 1896232 Total memory: 2031616 C:\herong>java -Xms32M -Xmx128M ShowMemory Free memory: 33222440 Total memory: 33357824 C:\herong>java -Xms64M -Xmx128M ShowMemory Free memory: 66514728 Total memory: 66650112

'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.

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_name jdb [options] -attach

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.

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 Hello Initializing jdb ... > stop in Hello.main Deferring breakpoint Hello.main. It will be set after the class is loaded. > run run Hello Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable > VM Started: Set deferred breakpoint Hello.main Breakpoint hit: "thread=main", Hello.main(), line=3 bci=0 3 System.out.println("Hello world!"); main[1] next Hello world!

> Step completed: "thread=main", Hello.main(), line=4 bci=8 4 } 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 Hello Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable Initializing 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: Option

Debugger jdb

Target java

1 2 3 4

Shared memory client Shared memory server Socket client Socket server

Shared memory server Shared memory client 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.

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 MyHello Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable Initializing jdb ... > VM Started: No frames on the current call stack main[1] stop in Hello.main Deferring 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=0 3 System.out.println("Hello world!"); main[1] list 1 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

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.Throwable Set deferred uncaught java.lang.Throwable Initializing jdb ... > VM Started: No frames on the current call stack main[1] stop in Hello.main Deferring 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=0 3 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:8888 java.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] thread suspend [thread id(s)] resume [thread id(s)] where [ | all] up [n frames] down [n frames]

--------

list threads set default thread suspend threads (default: all) resume threads (default: all) dump a thread's stack move up a thread's stack move down a thread's stack

kill interrupt

-- kill a thread with the given exception -- interrupt a thread

print dump eval set = locals

------

print value of expression print all object information evaluate expression (same as print) assign new value to a variable print all local variables

classes class methods fields

-----

list show list list

threadgroups threadgroup

-- list threadgroups -- set current threadgroup

currently known classes details of named class a class's methods a class's fields

stop in .[(argument_type,...)] -- set a breakpoint in a method stop at : -- set a breakpoint at a line clear .[(argument_type,...)] -- clear a breakpoint in a method clear : -- clear a breakpoint at a line clear -- list breakpoints catch [uncaught|caught|all] | -- break when specified exception occurs ignore [uncaught|caught|all] | -- cancel 'catch' watch [access|all] . -- watch access/modifications to a field unwatch [access|all] . -- discontinue watching trace methods [thread] -- trace method entry and exit untrace methods [thread] -- stop tracing method entry and exit step -- execute current line step up -- execute until the current method returns stepi -- execute current instruction next -- step one line (step OVER calls) cont -- continue execution from breakpoint list [line number|method] -- print source code use (or sourcepath) [source file path] -- display or change the source path classpath -- print classpath info from target VM monitor monitor unmonitor read

-----

execute specified command at stop time list monitors delete a monitor read and execute a command file

lock threadlocks [thread id]

-- print lock info for an object -- print lock info for a thread

disablegc enablegc

-- prevent garbage collection of an object -- permit garbage collection of an object

!!

-- repeat last command -- repeat command n times

help (or ?) version exit (or quit)

-- list commands -- print version information -- 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 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 }

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 PrimeNumberSeeker Period, Current int, # primes 1, 2, 0 2, 12, 5 3, 22, 8 4, 32, 11 5, 42, 13 6, 52, 15 7, 62, 18 8, 72, 20 9, 82, 22 10, 92, 24 11, 102, 26 12, 112, 29 13, 122, 30 ... 53, 521, 98 54, 531, 99 55, 541, 100 56, 541, 100 57, 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.main Deferring breakpoint PrimeNumberSeeker.main. It will be set after the class is loaded. > run run PrimeNumberSeeker Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable > VM Started: Set deferred breakpoint PrimeNumberSeeker.main

Breakpoint hit: "thread=main", PrimeNumberSeeker.main(), line=13 13 System.out.println("Period, Current int, # primes"); main[1] stop in PrimeNumberSeeker.run Set breakpoint PrimeNumberSeeker.run main[1] cont Period, Current int, # primes 1, 2, 0 > Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=28 28 primes = new int[ceiling]; Thread-0[1] threads Group system: (java.lang.ref.Reference$ReferenceHandler)0xe2 Reference Handler (java.lang.ref.Finalizer$FinalizerThread)0xe1 Finalizer (java.lang.Thread)0xe0 Signal Dispatcher Group 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 all Signal 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...

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] next 2, 2, 0 > Step completed: "thread=Thread-0", PrimeNumberSeeker.run(), line=29 29 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] next 3, 2, 0 > 30 current++; Thread-0[1] next 4, 3, 0 > 31 int j = 2; Thread-0[1] next > 5, 3, 0 32 boolean isPrime = true; Thread-0[1] next 6, 3, 0 > 33 while (j while (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.

• •



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] next 7, 3, 0 > 37 if (isPrime) { Thread-0[1] print isPrime isPrime = true Thread-0[1] next 8, 3, 0 > 38

count++;

Thread-0[1] next 9, 3, 0 > 39

primes[count-1] = current;

Thread-0[1] print count count = 1 Thread-0[1] next > 10, 3, 1 42

sleep(delay);

Thread-0[1] list 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 } 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

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:19 Set breakpoint PrimeNumberSeeker:19 Thread-0[1] cont > Breakpoint hit: "thread=main", PrimeNumberSeeker.main(), line=19 bci=25 19 System.out.println( i+", "+t.current+", "+t.count); main[1] where all main: [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=25 19 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 ...

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 (PrimeNumberSeeker)0x118

main Thread-0

running running (at breakpoint)

main[1] thread 280 Thread-0[1] list Current method is native Thread-0[1] step out 11, 22, 8 > Step completed: "thread=Thread-0", PrimeNumberSeeker.run(), line=45 45 } Thread-0[1] list 41 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:

Thread-0[1] stop at PrimeNumberSeeker:39 Set breakpoint PrimeNumberSeeker:39 Thread-0[1] cont > Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=39 39 primes[count-1] = current; Thread-0[1] cont > Breakpoint hit: "thread=main", PrimeNumberSeeker.main(), line=19 19 System.out.println( i+", "+t.current+", "+t.count); main[1] cont > 12, 23, 9 Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=39 39 primes[count-1] = current; Thread-0[1] cont > Breakpoint hit: "thread=main", PrimeNumberSeeker.main(), line=19 19 System.out.println( i+", "+t.current+", "+t.count); main[1] suspend 1 main[1] cont > Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=39 39 primes[count-1] = current; Thread-0[1] cont > Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=39 39 primes[count-1] = current; Thread-0[1] cont > Breakpoint hit: "thread=Thread-0", PrimeNumberSeeker.run(), line=39 39 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.

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:

'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 ] [ -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:://...) 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:

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 {

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 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, # primes 1, 2, 0 2, 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 " 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

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 sun.tools.jconsole.JConsole PrimeNumberSeeker

PID 2204 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=" Here is what I did to run my PrimeNumberSeeker.java with the default JMX agent for remote monitoring connections:

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, # primes 1, 2, 0 2, 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, # primes 1, 2, 0 2, 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

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:

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

• •

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, # primes 1, 2, 0 2, 12, 5 3, 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 200 3812 sun.tools.jps.Jps -l -m -v -Dapplication.home=C:\Program Files\java\jdk1.6.0_02 -Xms8m

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:

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jstatd Could not create remote object access 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, # primes 1, 2, 0 2, 10, 4 ...

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:1099 Connection 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.policy 4080 sun.tools.jps.Jps -l -m -v rmi://localhost:1234 -Dapplication.home=C:\Program Files\java\jdk1.6.0_02 -Xms8m 2024 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.

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\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 -Xms8m 3868 GarbageCollection -Xms24m -Xmx24m 2924 PrimeNumberSeeker 10 200 2544 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

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 313.7 0.00 99.99 4.20 84.56 0.15 314.6 0.00 99.99 0.00 97.66 0.15 315.6 0.00 0.00 0.00 71.25 0.15 316.7 0.00 99.99 4.20 84.56 0.15 317.7 0.00 99.99 0.00 97.66 0.15 318.6 0.00 0.00 0.00 71.25 0.15 319.7 0.00 99.99 4.20 84.56 0.15 320.7 0.00 99.99 0.00 97.66 0.15 321.6 0.00 0.00 0.00 71.25 0.15 322.7 0.00 99.99 4.20 84.56 0.15 323.7 0.00 99.99 0.00 97.66 0.15 324.7 0.00 0.00 67.14 71.25 0.15 325.7 0.00 99.99 4.20 84.56 0.15 326.7 0.00 99.99 0.00 97.66 0.15 327.7 0.00 99.99 86.29 97.66 0.15 328.7 99.99 0.00 0.00 77.66 0.15 329.7 0.00 99.99 71.29 84.56 0.15 330.7 0.00 99.99 19.15 97.66 0.15 331.7 99.99 0.00 0.00 77.66 0.15 332.7 0.00 99.99 71.29 84.56 0.15 ...

YGC 2093 2100 2106 2113 2120 2126 2133 2140 2146 2153 2160 2166 2173 2180 2185 2192 2198 2205 2212 2218

YGCT 3.653 3.665 3.674 3.687 3.699 3.708 3.721 3.734 3.743 3.756 3.769 3.777 3.790 3.803 3.810 3.821 3.832 3.845 3.855 3.867

FGC 416 417 419 420 421 423 424 425 427 428 429 431 432 433 434 436 437 438 440 441

FGCT 13.998 14.023 14.090 14.124 14.158 14.225 14.259 14.293 14.360 14.394 14.428 14.495 14.528 14.563 14.588 14.656 14.690 14.723 14.791 14.825

GCT 17.651 17.688 17.764 17.811 17.858 17.933 17.980 18.027 18.103 18.149 18.196 18.272 18.319 18.366 18.397 18.476 18.522 18.568 18.646 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 25034752 22710400 25034752 ...

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 200 2544 sun.tools.jstatd.Jstatd -p 1234 -Dapplication.home=C:\jdk -Xms8m -Djava.security.policy=tools.policy 3028 sun.tools.jps.Jps -l -m -v rmi://localhost:1234 -Dapplication.home=C:\Program Files\java\jdk1.6.0_02 -Xms8m 3536 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 303.6 0.00 99.99 86.29 97.66 0.15 2025 3.589 304.6 99.99 0.00 35.16 77.66 0.15 2032 3.597 305.6 100.00 0.00 51.20 90.69 0.15 2039 3.610 ...

FGC FGCT GCT 402 13.500 17.089 404 13.559 17.155 405 13.592 17.202

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

Chapter - 9 JVM 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.

"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 (to connect to a running process) where is one of: -flag to -flag [+|-] to -flag = to -h | -help to

print the value of the named VM option enable or disable the named VM option set the named VM option to the given value 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.jar 3984 sun.tools.jps.Jps -l -m C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jinfo -flag ThreadStackSize 424 -XX:ThreadStackSize=0

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.jar 3124 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:

C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jstack -help Usage: jstack [-l] (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: 4997104 Total memory: 5177344 (Start another command window.) C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m 3296 LongSleep 2224 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()

java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) - locked (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 (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 (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) {

}

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 Thread Thread Thread

1: 2: 2: 1:

Holding Holding Waiting Waiting

lock 1... lock 2... for lock 1... 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 -m 1464 SimpleDeadLock

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 (a java.lang.Object) - locked (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 (a java.lang.Object) - locked (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 (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) - locked (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 (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 (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:

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

(object 0x229bd238, by "Thread-0" (object 0x229bd240, by "Thread-1"

Java stack information for the threads listed above: =================================================== "Thread-1": at SimpleDeadLock$Thread2.run(SimpleDeadLock.java:37) - waiting to lock (a java.lang.Object) - locked (a java.lang.Object) "Thread-0": at SimpleDeadLock$Thread1.run(SimpleDeadLock.java:24) - waiting to lock (a java.lang.Object) - locked (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 ] pid jmap [ option ] executable core jmap [ option ] [server-id@]remote-hostname-or-IP 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= 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.

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

Java class, number of qualified class names printed with '*' prefix. 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 (to print histogram of java object heap of the JVM process) jmap -dump: (to dump java heap of the JVM process) dump-options: format=b file=

binary default dump heap to

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

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 23725256 22710400 21618728 20523584 ...

memory: 25034752 25034752 25034752 25034752

(Start another command window.) C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m 492 sun.tools.jps.Jps -l -m 428 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 11: 42 4032 java.lang.Class 12: 58 1392 java.util.Hashtable$Entry 13: 16 1280 [Ljava.util.HashMap$Entry; 14: 27 1000 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 1MB 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=" command: C:\herong>\Progra~1\java\jdk1.6.0_02\bin\java -Xms24m -Xmx24m GarbageCollection Free/total 23725256 22710400 21618728 20523584

memory: 25034752 25034752 25034752 25034752

... (Start another command window.) C:\herong>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m 764 GarbageCollection 1204 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 ] [-refs ] [-port ] [-baseline ] [-debug ] [-version] [-h|-help] -stack false -refs false -port -exclude

Turn off tracking object allocation call stack. Turn off tracking of references to objects Set the port for the HTTP server. Default is 7000. Specify a file that lists data members that should be excluded from the reachableFrom query. -baseline 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 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



The file to read

For a dump file that contains multiple heap dumps, you may specify which dump in the file by appending "#" 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 2008 Snapshot read, resolving... Resolving 67324 objects... Chasing references, expect 13 dots............. Eliminating duplicate references............. Snapshot resolved. Started HTTP server on port 7000 Server 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.

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];

String[] l = new String[64*64]; for (int i=0; i
View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF