.
.
java.sun.com developers.sun.com
.
   View this issue as simple text April 20, 2004    

In this Issue

Welcome to the Core Java Technologies Tech Tips for April 20, 2004. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SE).

This issue covers:

-User Datagram Protocol Programming
-Garbage Collection and You

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.2.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.

For more Java technology content, visit these sites:

java.sun.com - The latest Java platform releases, tutorials, and newsletters.

java.net - A web forum for collaborating and building solutions together.

java.com - The marketplace for Java technology, applications and services.

.
.

USER DATAGRAM PROTOCOL PROGRAMMING

It's often the case that when someone shows some network programming that uses the standard J2SE libraries, the code is for the sockets-based model using the Transmission Control Protocol/Internet Protocol (TCP/IP). TCP/IP is used for internet communication tasks such as sending email through Simple Mail Transfer Protocol (SMTP), surfing the World Wide Web through Hypertext Transfer Protocol (HTTP), and browsing through newsgroups through Network News Transfer Protocol (NNTP). What TCP/IP guarantees is delivery of the communication.

In brief, the IP part of TCP/IP moves packets of data from node to node. The TCP part wraps source and destination addresses as well as ports with sequencing information and content. When a set of packets from a source address arrives at the destination, the destination host can resequence the packets into their original order such that the receiver can read the data in the original order it was sent.

If you're a user of classes such as Socket and URL, TCP/IP takes care of many of the details regarding communication. For example, TCP/IP determines which offset in the header to store the sequence and acknowledgment numbers for the TCP packet. In addition, encapsulating the TCP packet is something called an IP datagram packet. The packaging of datagrams when doing TCP/IP-based programming is also done for you.

But there might be cases where TCP/IP provides more than what you need. For example, what if you don't need to guarantee the delivery of the communication, or you don't want the delay introduced with retransmission of packets, or you don't need the data to be read in the original order it was sent? In these cases, you can use an alternative to TCP/IP called User Datagram Protocol (UDP). When working with UDP, you still send packets over the IP protocol, but there is no guarantee of delivery or order. Why might delivery not be important? Imagine creating a program that all machines in an office must run. Every few seconds each machine sends an "I'm alive" message to a central server. Does it matter if an "I'm alive" message is lost? The answer is typically no. There is nothing that the sender of the message can do besides resend the message, and it's going to send the same message in a few seconds anyway. Similarly, does it matter if the messages don't arrive in the exact order? Again, for this type of message: no, it doesn't matter. Do you really care if the 10:05 message arrives at 10:10? Not really. Of course, for high-end stock trading systems you don't want to lose pricing information, but for a low-priority stock ticker, does it really matter if you miss a price change? When it's time to make that stock trade, you will need to check again anyway. Actually, using TCP could be detrimental if missing packets get resent for realtime data. Timely, rather than orderly and reliable delivery, is more important in the realtime case.

UDP programming involves the DatagramPacket and DatagramSocket classes of the java.net package. The DatagramPacket contains the information to send, including the identification of where to send that data. The DatagramSocket is used to send and receive packets.

The DatagramPacket class includes six constructors:

  • DatagramPacket(byte[] buf, int length, InetAddress address, int port)
  • DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
  • DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)
  • DatagramPacket(byte[] buf, int length, SocketAddress address)
  • DatagramPacket(byte[] buf, int length)
  • DatagramPacket(byte[] buf, int offset, int length)

Notice that the list of constructors is organized into three pairs. The first two pairs of constructors are used to create a packet for sending. The constructors in the first pair use an InetAddress for the destination address. The constructors in the second pair use a SocketAddress. The final pair of constructors are used for receiving packets. No source or destination addresses are needed in these constructors.

After creating a packet, the process of sending or receiving it involves calling the send or receive method of DatagramSocket. More specifically, you create a packet, then you create a socket. After you create the socket, you call the send method of DatagramSocket to send the datagram packet or use the receive method of DatagramSocket to receive a packet. You can also use the same DatagramSocket to send and receive multiple packets, each going to different destinations and coming from different sources.

Here's an example that sends and receives a datagram packet:

   import java.io.*;
   import java.net.*;

   public class GetTime {
     final private static int DAYTIME_PORT = 13;
     public static void main(String args[]) throws 
             IOException {
       if (args.length == 0) {
         System.err.println
             ("Please specify daytime host");
         System.exit(-1);
       }
       String host = args[0];
       byte message[] = new byte[256];
       InetAddress address = InetAddress.getByName(host);
       System.out.println("Checking at: " + address);
       DatagramPacket packet = 
           new DatagramPacket(message, message.length, 
                   address, DAYTIME_PORT);
       DatagramSocket socket = new DatagramSocket();
       socket.send(packet);
       packet = 
           new DatagramPacket(message, message.length);
       socket.receive(packet);
       String time = new String(packet.getData());
       System.out.println(The time at " 
               + host + " is: " + time);
       socket.close();
     }
   }

By passing the name of a server running the daytime service to the program, you can get the time at the location for that machine. For example:

   java GetTime localhost
   Checking at: localhost/127.0.0.1
   The time at localhost is: Fri Apr  2 11:30:46 2004

One potential problem with this example relates to security. For security reasons, most web-accessible machines turn off non-essential services and disable UDP connections through their firewall. As such, you might not find an accessible machine running the daytime service. Linux users can start the service and connect to their own machines. Another option (and for those without a startable service), is to use the TimeServer shown below. TimeServer uses the same DatagramPacket and DatagramSocket classes to create the server side to this program.

The new DatagramSocket(DAYTIME_PORT) line in TimeServer means that you want to listen on whatever port is defined in DAYTIME_PORT. The program doesn't wait until you do the call to the receive method. As is the case when you send the request, you must create a packet for the data. The daytime service ignores the contents of the packet, but you must still create a packet to receive the request. To send back the response in a DatagramPacket, you need to ask the received packet where to send the response.

Here is the TimeServer program:

   import java.io.*;
   import java.net.*;
   import java.util.*;

   public class TimeServer {
     final private static int DAYTIME_PORT = 13;
     public static void main(String args[]) throws 
             IOException {
       DatagramSocket socket = 
             new DatagramSocket(DAYTIME_PORT);
       while (true) {
         byte buffer[] = new byte[256];
         DatagramPacket packet = 
             new DatagramPacket(buffer, buffer.length);
         socket.receive(packet);
         String date = new Date().toString();
         buffer = date.getBytes();
         // Get response address/port 
         // for client from packet
         InetAddress address = packet.getAddress();
         int port = packet.getPort();
         packet = new DatagramPacket(buffer, buffer.length, 
                 address, port);
         socket.send(packet);
       }
     }
   }

If you're on a machine which doesn't allow permission to create a service on a low port, such as 13, change the port in both the client GetTime class and the TimeServer class.

Compile and start the TimeServer class first. This will run forever, simply responding to time requests such as the one sent when you run the GetTime class.

If you aren't familiar with the daytime service, this is defined in RFC 867.

For more information about datagrams, see the networking trail in the Java Tutorial.

.
.

GARBAGE COLLECTION AND YOU

The January 2004 Technical Tip Monitoring Class Loading and Garbage Collection explored -verbose:gc, a command line option available with the java command line tool (the Java application launcher). If you don't mind -XX options (because they're non-standard), or if you like uniformity of options, or if you want to know what options you're turning on, then you can enter -verbose:gc as:

     -XX:+PrintGC -XX:+TraceClassUnloading

This what the -verbose:gc option is translated into.

The option requests reports of garbage collection events during execution of an application. In J2SE v1.4.2, there are many other command line options that control the garbage collector. If you want to optimize the performance of your applications, without changing any lines of code, you might want to use one or more of these options. This tip explores a number of these additional java command line options that control the garbage collector. This is not an exhaustive list of garbage collection tuning options.

The Java application launcher comes with both standard and nonstandard command-line switches. By exploring the following reference pages for your specific platform, you'll find information about the previously mentioned -verbose:gc option:

There are also some non-standard options listed in the reference pages. Run the java command-line tool with the standard option -X to show non-standard options for your platform.

On a Solaris machine, the output of running java -X is shown below:

   -Xmixed           mixed mode execution (default)
   -Xint             interpreted mode execution only
   -Xbootclasspath:<directories and zip/jar files separated by :>
                     set search path for bootstrap classes and 
                     resources
   -Xbootclasspath/a:<directories and zip/jar files separated by :>
                     append to end of bootstrap class path
   -Xbootclasspath/p:<directories and zip/jar files separated by :>
                     prepend in front of bootstrap class path
   -Xnoclassgc       disable class garbage collection
   -Xincgc           enable incremental garbage collection
   -Xloggc:<file>    log GC status to a file with time stamps
   -Xbatch           disable background compilation
   -Xms<size>        set initial Java heap size
   -Xmx<size>        set maximum Java heap size
   -Xss<size>        set java thread stack size
   -Xprof            output cpu profiling data
   -Xrunhprof[:help]|[:<option>=<value>, ...]
                     perform JVMPI heap, cpu, or monitor profiling
   -Xdebug           enable remote debugging
   -Xfuture          enable strictest checks, anticipating future 
                     default
   -Xrs              reduce use of OS signals by Java/VM (see 
                     documentation)
   -Xcheck:jni       perform additional checks for JNI functions
   
  The -X options are non-standard and subject to change without 
  notice.

Notice the last line of output. It underscores the fact that you should use these options at your own risk.

The three specific non-standard options for garbage collection are -Xnoclassgc, -Xincgc, and -Xloggc:<file>. If you specify the -Xnoclassgc option, collections happen, but classes are not collected from the permanent generation. This means that a collection frees up no space (at least, no space from loaded classes). If you ran out of space for loaded classes while trying to load a class, the collection won't resolve the problem.

In Sun's 1.4.2 implementation, -Xincgc is equivalent to the -XX:+UseTrainGC option. That is, -Xincgc uses the "train" collector for the old generation, rather than the "serial" collector you get by default. (The concept of "generations" is covered later in this tip.) The train collector has some performance overhead (about 10%). It also has some space overhead because it doesn't collect the entire old generation at once. It does have the advantage of working incrementally, so that the pauses it introduces are usually quite small. In Sun's beta 1.5.0 release, the -Xincgc flag will invoke the mostly-concurrent mark sweep (CMS) collector rather than the train. That's because, the CMS collector is almost uniformly better than the train.

By specifying the -Xloggc option, you direct the equivalent of the -verbose:gc output to a file. As compared to the output produced by -verbose:gc, the output produced by -Xloggc includes one additional item of information: the time of the garbage collection (from the time of the first collection in the application). This is shown in the following -Xloggc sample output:

   0.000: [GC 512K->153K(1984K), 0.0198483 secs]
   0.372: [GC 506K->281K(1984K), 0.0206428 secs]
   0.393: [Full GC 281K->281K(1984K), 0.0888926 secs]
   0.519: [GC 947K->941K(1984K), 0.0045715 secs]
   0.524: [Full GC 941K->941K(1984K), 0.0797666 secs]
   0.650: [GC 2107K->1597K(2808K), 0.0013546 secs]
   0.838: [GC 2107K->1700K(2808K), 0.0116557 secs

You can enable the timestamps on the -Xloggc output without redirecting to a file, by specifying the -XX:+PrintGCTimeStamps option.

In addition to -Xnoclassgc, -Xincgc, and -Xloggc:<file>, there are other options that control the garbage collector. For example, you can change the memory allocation pool sizes with -Xms and -Xmx to indirectly affect when the collector runs. By specifying a larger -Xms, you start off with a larger Java object heap. This means that it will take you longer to fill up the heap, and as a result, it delays (but doesn't avoid) a collection. A larger -Xms also consumes more system resources. By specifying a larger -Xmx, you allow the Java object heap to grow (if needed) to a larger size. A larger object heap needs to be collected less often, everything else being equal. However, a larger heap takes more time to collect. So these options allow you to trade more frequent but shorter collections against less frequent but longer collections. Because each collection has a certain overhead, the better approach depends on your specific requirements.

In addition to -Xms and -Xmx, there are several non-standard options that affect garbage collection. These are not even listed in the java -X help output. Because the options are non-standard, you need two X's to enable them.

If you want to adjust the minimum or maximum heap free percentage (the default range is 40-70%), you can use the -XX:MinHeapFreeRatio=<Minimum> and -XX:MaxHeapFreeRatio=<Maximum> options. If you make the minimum too small, the heap won't have much free space after a collection. So you'll likely need to collect again in the near future. If you make the minimum larger, then you will have more "head room," and will delay the time to the next collection. The disadvantage of a large -XX:MinHeapFreeRatio is that system memory is tied up for this virtual machine, and is not available for other applications on your machine.

Other non-standard options in the -XX set impact how the garbage collector operates. The -XX:+UseConcMarkSweepGC command-line flag (short for "concurrent mark sweep garbage collection") turns on the concurrent garbage collector. The -XX:+UseConcMarkSweepGC collector collects the old generation concurrently. Because it's usually the old generation collections (for example, full collections) that take a long time, turning on the concurrent garbage collector is good. It trades the utilization of processing power that would otherwise be available to the application for shorter garbage collection pause times. The -XX:+UseParallelGC command-line flag enables parallel garbage collecting. The -XX:+UseParallelGC collector only collects the young generation with multiple processors. This approach helps with throughput, but it doesn't reduce full collection pause times.

Yet another option of interest is -XX:+PrintGCDetails, which shows, at each collection, what happened in each of the generations. (Except that it doesn't show the details about the permanent generation. That is fixed in JDK 1.5.0.)

Here's an example that shows the -XX:+PrintGCDetails in use with the SwingSet2 demo. (Note that the lines of output are broken to fit the confines of this tip.)

   java -Xloggc:details.out -XX:+PrintGCDetails -jar
    /home/eo86671/j2sdk1.4.2/demo/jfc/SwingSet2/SwingSet2.jar

   0.000: [GC 0.000: [DefNew: 511K->64K(576K), 0.0182344 secs] 
        511K->153K(1984K), 0.0185255 secs]
   1.387: [GC 1.387: [DefNew: 417K->64K(576K), 0.0192086 secs]
        1.407: [Tenured: 217K->281K(1408K), 0.0725645 secs] 
        506K->281K(1984K), 0.0923346 secs]
   1.559: [GC 1.559: [DefNew: 10K->3K(576K), 0.0044098 secs]
        1.564: [Tenured: 937K->941K(1408K), 0.0741569 secs]
        948K->941K(1984K), 0.0790573 secs]
   1.703: [GC 1.703: [DefNew: 510K->0K(576K), 0.0011627 secs] 
        2107K->1597K(2808K), 0.0013820 secs]
   2.210: [GC 2.210: [DefNew: 509K->64K(576K), 0.0112637 secs] 
        2107K->1710K(2808K), 0.0115942 secs]
   2.927: [GC 2.927: [DefNew: 575K->64K(576K), 0.0170128 secs]
        2222K->1841K(2808K), 0.0173293 secs]
   8.430: [GC 8.430: [DefNew: 576K->64K(576K), 0.0142839 secs] 
        2353K->2025K(2808K), 0.0156266 secs]
   8.823: [GC 8.823: [DefNew: 494K->64K(576K), 0.0164915 secs] 
        2456K->2243K(2808K), 0.0166323 secs]
   8.856: [GC 8.856: [DefNew: 569K->41K(576K), 0.0058505 secs]
        8.862: [Tenured: 2341K->1656K(2360K), 0.1464764 secs] 
        2749K->1656K(2936K), 0.1526133 secs]

Try tweaking the -Xms and -Xmx options to see how the changes affect the results, possibly lengthening time between collections or reducing each specific pause.

There's been some previous mention of "generations" of heap space. If you're wondering what this means, here's a short description. The heap in the 1.4.2 JRE is divided into three generations: young, old, and permanent. The young generation is where objects are born. The size of this generation is controlled by the -XX:NewSize and -XX:MaxNewSize options. As new objects are tenured, they are promoted to the old generation. The old generation size is computed as the total heap size (-Xms and -Xmx) minus the young generation size (-XX:NewSize and -XX:MaxNewSize). The young generation is better specified with -XX:NewRatio= rather than explicit sizes, as then it adjusts as the total size of the heap adjusts. The chosen size determines the collection frequency versus the duration of the collection. Some applications require shorter pause times, while others need collector efficiency. (And for many applications, you don't need this level of tuning at all.)

One last GC option to mention is -XX:+DisableExplicitGC. Use this option if you want the system to ignore suggestions to run the garbage collector with System.gc() calls. The garbage collector will still run when needed, just not when a programmer suggests to the system that it should. Is it a good idea to ignore the suggestion? Probably not. After all, the programmer thought it would be a good time to run the garbage collector. Of course, if you are using a shared library, and the execution context is different than the original programmer envisioned, the original programmer thoughts might not be valid in the new situation.

For more information about garbage collection-related options, see Tuning Garbage Collection with the 1.4.2 Java Virtual Machine. When tuning, be sure to identify what you are tuning for: such as better performance, shorter pauses, or a smaller footprint. As your program evolves, you'll need to reevaluate tuning options. And, as the JVM gets updated, remember to reevaluate the options you choose. Keep in mind that most of the options mentioned in this tip are specific to both Sun's runtime environment and the 1.4.2 release of that environment. The 1.5.0 release has its own set of controls and defaults.

.
.
Reader Feedback
Excellent   Good   Fair   Poor  

If you have other comments or ideas for future technical tips, please type them here:

Comments:
If you would like a reply to your comment, please submit your email address:
Note: We may not respond to all submitted comments.

Have a question about Java programming? Use Java Online Support.

.
.

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developers.sun.com/dispatcher.jsp?uid=6910008


Comments? Send your feedback on the Core Java Technologies Tech Tips to: http://developers.sun.com/contact/feedback.jsp?category=newslet

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EE).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2ME).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/developer/JDCTechTips/index.html


Copyright 2004 Sun Microsystems, Inc. All rights reserved.
4150 Network Circle, Santa Clara, CA 95054 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/developer/copyright.html


Java, J2SE, J2EE, J2ME, and all Java-based marks are trademarks or registered trademarks (http://www.sun.com/suntrademarks/) of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems,
Inc.
.
.