Sun Java Solaris Communities My SDN Account Join SDN
 
Article

Developing Java Applications on the Solaris OS

 
By Rick Palkovic, March 2007  

The platform independence of Java applications lets developers capitalize on the “write once, run anywhere” paradigm. Moreover, the popularity of the Java programming language has motivated platform providers to compete in producing the best performance for Java benchmark tests, particularly on the server side. As a result, enterprises have many choices when deploying high-performance application servers in a Java environment, the major consideration being level of performance for dollar spent.

Get Solaris OS and Java EE SDK

For more about the Solaris 10 OS, see the Sun Microsystems Solaris 10 page. For more about the Java EE SDK, see Java EE at a Glance.
Information, downloads, support, and more.
 

Java developers have a similarly broad number of choices when deciding on a platform on which to develop their applications and stage their deployments. When evaluating a Java development system, developers typically consider at least the following points:

  • A mature, secure, and stable operating system. Chasing bugs in an application is hard enough without having to debug the OS as well.

  • Java specific diagnostic, debugging, and monitoring tools.

  • A high-performance Java Virtual Machine (JVM) bytecode execution engine and dynamic optimizing compilers.

  • A high-performance integrated development environment (IDE). A good IDE shortens the code-compile-deploy-test cycle.

The choice of the best Java development platform is complicated by the fact that developers of Java programming tools, like other Java developers, typically do their best to design tools that run equally well on any platform. Other than the raw horsepower of a platform's underlying hardware, then, are all Java development environments created equal? Not by a long shot.

This article does not attempt a head-to-head comparison among operating systems, but instead examines the ways the Solaris OS integrates its native capabilities with the JVM and Java development tools. Unless otherwise indicated, references in this article to the Solaris OS refer to the Solaris 10 Operating System.

 
Contents
 
Java Applications on the Solaris OS: Underlying Advantages
The Solaris OS: A Mature and Stable Operating System
The NetBeans IDE
DTrace
Java Stack Trace
Other Observability Tools
Sun Studio Performance Analyzer
Solaris Containers
HotSpot JVM, Server Ergonomics, and Performance Tuning
ZFS File System
Conclusion
Acknowledgments
References
 
 
Java Applications on the Solaris OS: Underlying Advantages

Before delving into tools and technologies, consider two basic advantages of the Solaris OS.

First, the Solaris OS is the tier 1 Java development platform. Sun Microsystems develops much of the HotSpot JVM and the Java SE JDK on the Solaris OS first. Likewise, the Solaris OS is a key performance optimization platform for Java technology.

Second, the Solaris OS is unique in that support for the Java platform is included with a Solaris support contract. Sun Java Desktop System, Release 3 and Java 2 Platform, Standard Edition 5 are integrated and supported under a Solaris Service Plan (with certain component exceptions). No other operating system provides similar Java support.

 
The Solaris OS: A Mature and Stable Operating System

The Solaris Operating System's SunOS core provides UNIX shell commands and tools developers have become accustomed to, and complies with the Open Group’s Unix 98 specifications (also known as SUS version 2). The Solaris 10 OS adds a GUI windowing system, web browser, and other tools to the SunOS core. The SunOS core, currently derived from the AT&T SVR4.0 flavor of UNIX software, ships with hundreds of utilities and user-level programs that provide backwards compatibility for legacy applications and scripts dating from SunOS 4.x, a BSD flavor.

As a mature and stable operating system, the Solaris OS has much to recommend it.

  • It is available for both SPARC and x86 platforms, and is supported for thousands of open source and ISV applications.

  • With the release of OpenSolaris in June 2005, the core source code for the Solaris OS has become free to the open source community under an OSI-approved open-source license, the CDDL. An open-source community effort is also under way to port OpenSolaris to Power/PowerPC architectures.

  • It has the largest installed base of any commercial UNIX or Linux distribution. As of October 2006, in excess of 7 million copies were registered.

  • If testing and quality assurance are included as part of the development process, then the well-recognized scalability benefits of the Solaris OS are also advantages. Realistic load testing requires an industry-standard operating system and typical server hardware.

The widespread use and stability of the Solaris OS argues for its use as a deployment platform for enterprise and web-based applications. From a Java developer's perspective, it is more important to consider how well its native features support development in general, and how well its available development tools measure up, both in quantity and quality. These tools (preferably free and standards-based) include IDEs, diagnostic and debugging tools, compilers, and the JVM.

 
The NetBeans IDE

The NetBeans IDE started as a Charles University student project in Prague in 1996. Sun Microsystems purchased the technology in 1999 and converted it to open source in 2000. Although it has been ported to all major platforms, the Solaris OS is still the tier 1 platform for the latest NetBeans releases. The NetBeans IDE can be downloaded for free from Sun Microsystems.

The NetBeans IDE supports development of Java desktop, enterprise and web applications — including Java SE, Enterprise JavaBeans (EJB) technology, and Java ME mobile applications. The IDE uses the open source tool Ant to automate its project build processes. It also incorporates version control and refactoring.

All the functions of the NetBeans IDE are provided by modules, which allow the IDE to be extended. New features, such as support for other programming languages, can be added by installing additional modules. With the Visual Web Pack module, the NetBeans IDE provides drag-and-drop GUI building capabilities for web applications. The NetBeans Enterprise Pack supports development of Java EE applications and includes SOA visual design tools, XML schema tools, web services orchestration for BPEL, and UML modeling.

Most importantly, the Java EE compliant code produced using the NetBeans IDE (and its derivatives Sun Java Studio Creator IDE and Sun Java Studio Enterprise) allows your application to move from one compliant server to another safely, regardless of server manufacturer and without licensing fees.

 
Other IDEs
 

Several additional IDEs have been developed for the Solaris OS as well as other platforms. Those based on the NetBeans IDE include Sun Java Studio Creator and Sun Java Studio Enterprise. These and other development tools can be downloaded for free from Sun Microsystems.

Other open source and third-party IDEs are also available, including the Eclipse IDE for the Solaris OS on x86 platforms.

 
DTrace

DTrace is a dynamic tracing facility that is built into the Solaris OS. It can be used to examine the behavior both of user programs and of the operating system itself. DTrace enables you to explore your system to understand how it works, track down performance problems across many layers of software, and locate the source of errors.

Debugging a production application with crash dumps and memory snapshots is simply not practical. With DTrace, you can probe the system to provide answers to such questions as “Where did the signal to kill my process come from?” and “Why has a particular thread been preempted?”

The Solaris 10 OS is instrumented with more than 30,000 access points that can be probed by DTrace, and you can add additional probes as needed. Using DTrace, you can collect data from specific points in the operating system to see how your application is behaving as it interacts with the Solaris OS. DTrace was designed to be able to debug live development or production systems, providing a system overview that is impossible to see with other tools.

Java SE6, released in December 2006, contains built-in DTrace probes that you can easily use to collect detailed information about a running Java application.

Because DTrace is part of the OpenSolaris community, it will inevitably be ported to other operating systems. But, as with other tools that originated with Sun Microsystems, it is likely that the latest DTrace features will be tested and will appear first on the Solaris OS.

 
DTrace Probes and Providers
 

A DTrace probe is an instrumentation point in the Solaris OS — a location in the system that you can examine to get system details.

Four attributes of a probe form a quadruple that identifies the probe uniquely:

provider:module:function:name
        

  • Provider – Probes are made available by providers, which do the heavy lifting for DTrace. syscall is an example of a provider.

  • Module – Each probe is associated with the module that it instruments. Modules have the names of kernel modules: ufs, nfs, libc and so on.

  • Function – Each probe is likewise associated with the function that it instruments. An example of a function is malloc, a function in the module libc.

  • Name – Each probe also has a name, such as enter or return.

This naming convention provides human readability for the probes. The wildcard characters “*” and “?” can be used to form the name of any element in the quadruple. Moreover, if you leave out an attribute, all values of the attribute are included. For example, consider the following quadruple:

syscall:::entry
        

The syscall provider probes at the entry and return of every system call. In this quadruple, the module and function values are omitted, so a match will occur whenever a system call is entered.

As another example, consider the following quadruple:

syscall:open::entry
        

This quadruple matches the entry of all open system calls.

 
How DTrace Works
 

The D program source is represented in the figure by a.d or b.d. When you run the program with the dtrace command, the command interprets the program and writes it into an intermediate record using the libdtrace library. As the source is interpreted, it is tested to determine that it is safe to run on a live system. DTrace then accepts the intermediate record and loads it into the kernel, transforming it into a kernel module.

DTrace – How It Works
Figure 1: DTrace – How It Works
 

DTrace providers in the kernel are awakened by probe descriptions in the program kernel module and provide callbacks into the program when a probe is fired. The callbacks cause the action statements in the program to be executed. Typically, these action statements collect, prune, and report data.

A provider has been developed for Java code. The provider allows DTrace to collect intelligent information about Java applications. For example, you can find when the garbage collector runs, and collect information on method calls.

 
Programming with the D Language
 

DTrace programs are typically quite simple. Probe descriptions enable and monitor a probe, and action statements following the probe descriptions describe what to do when a probe fires.

D Language programs have the following structure:

#!/usr/sbin/dtrace -s
provider:module:function:name
/predicate/
{
   action statements
}

The first line identifies the file as a D language script. This line is not necessary if the script is executed with the dtrace command, as follows:

dtrace [options] script_name
        

The second line in the script identifies the probe (or set of probes).

The third line is an optional predicate, demarcated by slash characters. The action statements that follow are executed only when the predicate evaluates as true. The predicate section acts as a filter by letting you set conditions to determine when the action statements execute. You can set conditions based on many criteria, such as the name of an executable.

The action statements let you report or collect information on some state of the system. Some probes provide generic information, others provide information that is quite specific.

 
A Trivial Example D Program
 

A special probe named BEGIN fires whenever a DTrace program starts; a similar probe named END fires whenever a DTrace program ends. When the following D-language program executes, the BEGIN probe fires, the string “Hello World” is printed, and the program exits. As the program exits, the END probe fires, and the program prints “Goodbye Cruel World.” The program has no predicate.

#!/usr/sbin/dtrace -s
BEGIN
{
  printf("Hello World\n");
  exit(0);
}

END
{
  printf("Goodbye Cruel World\n");
}

 
Example D Programs
 

In the following program, probes are enabled every time a system call is executed (syscall:::entry). The predicate clause (/execname=="bash"/) limits the action statements that follow to only the system calls initiated by the bash executable. You could instead use the executable name xsun for the windowing system, for example, or java for a Java application.

The action statement causes the probefnc, a built-in variable, to be printed.

#!/usr/sbin/dtrace -s
syscall:::entry

/execname=="bash"/
{
          printf("%s called\n",probefnc);
}

You can easily modify the above script to print only the
system calls made by 'java.'

#!/usr/sbin/dtrace -s
syscall:::entry
/execname == "java"/
{
          printf("Java(%d) called syscall %s\n", pid, probefunc);
}

JDK 6.0 has two DTrace providers built in that provide information about the JVM: hotspot and hotspot_jni. The hotspot_jni provider collects details about JNI calls from your Java application.

Consider the following simple script that prints the time when garbage collection runs for a target application. The built-in variable walltimestamp contains the absolute time (nanoseconds since 00:00 Universal Coordinated Time, January 1, 1970). The $target variable is the process id passed to the script through the -p option.

The gc-begin probe fires when the garbage collector starts.

hotspot$target:::gc-begin
{
        printf("GC started at %Y\n",walltimestamp);
}

To run this script, you must first find the process id of the Java application. Then use the process id in the command line when you execute the script. For example, if the script were named hotspot_gc.d and the process id of the application were 7792, your command line would be as follows:

    dtrace -qs hotspot_gc.d -p 7792
        

In the following figure, the script is run for the jedit process, which has a pid of 7792. Note that you could also use jps to list the instrumented HotSpot Java Virtual Machines (JVMs) on the target system. The jps tool is limited to reporting information on JVMs for which it has the access permissions.

DTrace  Output1
Figure 2: DTrace Output
 

You can modify the script as follows to determine how much time was spent in each garbage collection event.

hotspot$target:::gc-begin
{
        printf("GC started at %Y\n",walltimestamp);
        self->ts = timestamp;
}

hotspot$target:::gc-end
/self->ts/
{
        printf("\tand ran for %d milli secs\n",(timestamp - self->ts)/1000000);
        self->ts = 0;
}

The gc-begin probe fires at the start of the garbage collection event. Action statements print the absolute start time, and the variable self->ts stores the relative time of the start event.

The gc-end probe fires at the end of each garbage collection event. The built-in variable timestamp is used to calculate the difference between the times that the begin and end probes fire. timestamp should be used only for relative computations such as this one.

 
Java Stack Trace

jstack prints Java stack traces of Java threads for a given Java process or core file or a remote debug server. Beginning with J2SE 5.0 update 1, jstack is available as a DTrace action. jstack prints mixed-mode stack traces (frames in both Java and native C/C++ languages, for example), optionally including native frames. You can also print information about locks and deadlocks.

jstack is useful in tracking down problems that involve system hangs or looping processes. A hang can occur for many reasons, but often stems from a deadlock in application code, API code, or library code. Sometimes an apparent hang turns out to be, in fact, an infinite loop that consumes all available CPU cycles.

The first step in diagnosing a hung system is to discover if the virtual machine process is idle or if a looping thread is consuming all CPU cycles. You must use an operating system utility to make this determination. On the Solaris OS, you can use the command prstat -L -p pid  to report the statistics for all light-weight processes in the target process and thus identify the threads that are consuming the most CPU cycles.

If a VM process appears to be looping, the first step in discovering the source of the problem is to try to get a thread dump. But, what if the process is running as a background process, or the JVM output is directed to an unknown location? In such cases, the application console and standard input/output is not available. You can, however, use the jstack utility to obtain the stack thread. Use the jstack -F pid  option to force a stack dump of the looping process. By focusing on threads that are in the RUNNABLE state, you can narrow down your search for the looping thread.

You can also run a DTrace agent library inside the Java Virtual Machine (JVM) to provide DTrace probes that are specific to the JVM and the Java platform. The agent, called dvmti, uses the Java Virtual Machine Tool Interface (JVM TI) to request various JVM events and provide DTrace probes in the callback code for those events.

 
Other Observability Tools

In addition to the integration of DTrace with Java technology, Java EE software contains many other observability tools. These tools are available on other platforms, but the integration of many of them with the Solaris gcore(1) utility deserves mention.

Postmortem tools can provide information about hung Java processes or Java core dumps. The Java tools are designed to work with the Solaris gcore utility. After you use gcore to take a core dump of the system, you can analyze the core dump using any of the following tools:

  • jinfo – prints Java configuration information for a given Java process or core file or a remote debug server.

  • jmap – displays information similar to that of the Solaris pmap tool.

  • jstack– as already discussed, jstack is equivalent to the Solaris pstack tool, and can also be used with DTrace.

  • jsadebugd – attaches to a Java process or core file and acts as a debug server. Remote clients such as jstack, jmap, and jinfo can attach to the server using Java RMI.

  • jhat– a Java heap dump browser.
 
Sun Studio Performance Analyzer

One additional development tool deserves note: the Sun Studio Performance Analyzer, part of the Sun Studio Compilers and Tools suite.

When profiling a Java application, the Sun Studio Performance Analyzer collects data on the JVM as it runs the Java application. Clock profiling, hardware-counter profiling, and synchronization tracing are all supported.

The Sun Studio Performance Analyzer collects data by recording events in the life of each LWP of the Java process, along with the callstack at the time of the event.

Java applications have unique characteristics that make profiling more difficult than for applications written in more traditional, natively compiled languages. For any method in a Java program, there is a version that is interpreted by the Hotspot JVM, and there may be another version that has been dynamically compiled by the HotSpot JVM. Moreover, the Java application may call precompiled native methods directly. In these mixed-mode Java applications, two callstacks are meaningful: a Java callstack and a machine callstack.

Both callstacks are recorded during profiling by Sun Studio Performance Analyzer, and are reconciled during analysis. Profiling results can be shown with a GUI Analyzer or from the command line. Three different representations are provided:

  • User Representation shows compiled and interpreted Java methods by name and shows native methods in their natural form.

  • Expert Representation is similar to the User Representation, except that some additional details of the JVM internals are exposed.

  • Machine Representation shows functions from the JVM itself, rather than from the Java application being interpreted by the JVM, along with any compiled methods and native methods.
 
Solaris Containers

Solaris Containers enable you to configure a container that acts as a completely separate instance of the Solaris OS, resulting in resource, fault, and security isolation. Solaris Containers are a type of operating system virtualization, and are made up of two major components: Solaris Zones and Solaris Resource Manager (SRM). SRM manages the physical system resources every Container receives, and Solaris Zones control the namespace isolation.

The advantages of Solaris Containers for deployment are obvious:

  • Reduced management costs through server consolidation, and a reduced number of operating system instances. To reduce costs, businesses are eager to consolidate deployed applications onto fewer servers.

  • Increased resource utilization with dynamic resource reallocation between Containers.

  • Increased service availability by minimizing fault propagation and security violations between applications.

  • Increased flexibility because software-based Containers can be dynamically reconfigured.

  • Increased accuracy and flexibility of accounting, based on workloads rather than systems or processes.

Advantages for developers are obvious as well:

  • A development group can share a single server with other users within the organization. The productivity of other groups will not be endangered because each Solaris Container is isolated and secure.

  • For an individual developer, Solaris Containers permit several isolated execution environments to coexist on the same server, allowing independent development and testing of alternate configurations.

Solaris Containers for Linux Applications allow Linux applications to run unmodified on the Solaris OS. By leveraging all the benefits of Solaris Containers, this feature combines the best of virtualization, resource management, and OS flexibility.

 
HotSpot JVM, Server Ergonomics, and Performance Tuning

Server ergonomics for servers was introduced in the Hotspot JVM for Java SE 5.0. It has greatly reduced application tuning time for server applications, particularly with heap sizing and advanced garbage collector (GC) tuning. Based upon the platform configuration, it will select a compiler, Java heap configuration, and garbage collector that produce good to excellent performance for most applications. In many cases, out-of-the-box settings provide the best tuning options for your application. The HotSpot JVM has been ported to all major operating systems, but the Solaris OS remains the tier 1 development platform.

To implement smart tuning, the JVM determines the type of machine the JVM is running on. If the machine is server class, the Hotspot JVM allocates a larger heap, implements parallel garbage collection (GC), and employs a server compiler. The server compiler is designed for long-lived applications in which runtime performance and high throughput are important, while start-up time and memory footprint are not.

If the machine is client class, the JVM allocates a minimal heap, implements serial garbage collection, and employs a client compiler. The client compiler is designed for applications in which start-up time and small memory footprint are most important.

Whether the JVM detects a server or client class machine, it uses an adaptive heap sizing policy to tune performance automatically. For developers, automated tuning through server ergonomics means that you can usually obtain near optimum performance from your application without time-consuming hand tuning of heap sizes.

 
ZFS File System

The ZFS file system, introduced in the Solaris 10 OS, is typically seen as a benefit to system administrators — it dramatically simplifies storage administration, provides data integrity and high performance, and provides essentially limitless scalability.

While developers typically take file systems for granted and assume that one is as good as another for practical purposes, they are beginning to recognize specific benefits from ZFS.

One Solaris developer uses ZFS to maintain several development workspaces on his laptop computer. The workspaces are snapshots of the entire Solaris development source tree, each about 2 GB in size. With a few ZFS commands, he maintains a single primary workspace locally, and as many smaller workspaces (composed of diffs) as he needs. Using this approach, he can also create a scratch build workspace to keep build artifacts out of his development workspaces.

For this developer, ZFS provides many large workspaces on a relatively small hard drive, and lets him manage them easily. While some of the purposes could have been achieved with loopback mounts, the ZFS techniques provide a much more efficient use of disk space.

The ease of administration inherent in ZFS can be very convenient for developers. For example, ZFS makes it easy to share a file system between multiple installations of the Solaris OS on a single machine. To share a file system, create a ZFS pool and mount it on each different Solaris installation. On each Solaris installation, provide an initialization script that performs a zpool import on startup, and a zpool export on shutdown. With ZFS, any file system you create on the ZFS pool does not need to be explicitly added or mounted by hand. ZFS automatically mounts every file system you create on the ZFS pool.

 
Conclusion

As an operating system for Java development, the Solaris OS provides many of the same advantages it does for development in traditional languages:

  • Maturity, stability, and wide acceptance.

  • A full complement of IDE, debugging, and profiling tools.

  • Advanced features such as ZFS that provide scalability and ease of maintenance.

Java specific advantages include profiling tools that are integrated with the HotSpot Java VM.

Finally, some additional comparisons with competing operating systems are inevitable:

Compared with Microsoft Windows, the Solaris OS provides:

  • Larger Java heap sizes in 32-bit address spaces

  • Remote display of Java applications

Finally, the OpenSolaris community has erased the perceived advantages of Linux and other open-source OS alternatives. Open source operating systems, which now include the Solaris OS, must now compete on the basis of performance, usability, interoperability, cost of service, and overall cost of ownership.

 
Acknowledgments

Thanks to all who provided information for this article, especially Brian Doherty, Angelo Rajadurai, Scott Oaks, Marty Itzkowitz, and Alexander Kolbasov.

References
Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.
Rick Palkovic Rick Palkovic is a staff writer for Sun Developer Network. He has written about the Solaris OS and Java technologies for longer than he likes to admit, composing everything from man pages to technical white papers.