Monday, April 25, 2011

Memory Leak in ObjectOutputStream

A memory leak exists in ObjectOutputStream that can cause your application to throw OutOfMemoryError.
 
To demonstrate this I have written a simple application that sends a lot (1500 per second) serialized small objects over the ObjectOutputStream via TCP connection.
During the testing I have discovered memory leaks and application crashed due to "out of memory".
First I have used a method ObjectOutputStream.writeObject(o).
This of course casued growing:
  private final HandleTable handles;
 private final ReplaceTable subs;
in ObjectOutputStream. This has prevented my objects to be garbage collected after sending and that was my intention.

My test does not need to keep cached objects so I have changed implementation to to ObjectOutputStream.writeUnshared(o).

My expectation was that this will end gowring tables in ObjectOutputStream.

Unfortunately  handles table have been still growing but my objects have been garbage collected. I have classified this as "memory leak".
Looking deeper into the problem the I have found possible reason.
The order of metthod calls is as follows:
ObjectOutputStream.writeUnshared(obj)
--- writeObject0(obj, true);
------ writeOrdinaryObject(obj, desc, unshared);
--------- handles.assign(unshared ? null : obj);
This last call is really:
    handles.assign(null);

Here you have a code for  ObjectOutputStream.HandleTable.assign(Object)
int assign(Object obj) {
    if (size >= next.length) {
growEntries();
    }
    if (size >= threshold) {
growSpine();
    }
    insert(obj, size);
    return size++;
}

What you can see here is that size of handle table is growing even if  this function is called with "null" argument. Increasing handles table is causing VM to run out of memory after some time.
 
WORKAROUND:
Call from time to time:
   ObjectOutputStream.reset()
This will clear handles.

Note: You can never be sure that you will reset it on time in live system.

Sunday, April 24, 2011

Java SE 7 - Stream Control Transport Protocol (SCTP) in Java

Stream Control Transport Protocol (SCTP) in Java
 
Java SE 7 introduced support for Stream Control Transport Protocol (SCTP). The work of defining the API and reference implementation was done through the sctp openjdk project.
 
Brief Introduction to SCTP


The Stream Control Transport Protocol (SCTP) is a reliable, message-oriented, transport protocol existing at an equivalent level with UDP (User Datagram Protocol) and TCP (Transmission Control Protocol). SCTP is session oriented, and an association between the endpoints must be established before any data can be transmitted.
 
SCTP has direct support for multi-homing, meaning that an endpoint may be represented by more than one address and each address may be used for sending and receiving data, thus providing network redundancy. The connection between two endpoints is referred to as an association between those endpoints. Endpoints can exchange a list of addresses during association setup. One address is designated as the primary address, this is the default address that the peer will use for sending data. A single port number is used across the entire address list at an endpoint for a specific session.
 
SCTP is message based. I/O operations operate upon messages and message boundaries are preserved. Each association may support multiple independent logical streams. Each stream represents a sequence of messages within a single association and streams are independent of one another, meaning that stream identifiers and sequence numbers are included in the data packet to allow sequencing of messages on a per-stream basis.
 
Key Features of SCTP

  • Message framing
  • Reliable transport service
  • Session-oriented
  • Ordered and unordered message delivery
  • Multi-Homing
    • Association between exactly two endpoints
    • Each endpoint may be represented by multiple IP addresses
    • Provides failover and redundancy
  • Multi-Streaming
    • Data partitioned into multiple streams
    • Independent sequenced delivery
  • Eliminates head-of-line blocking

Support for SCTP in JDK 7

The Java API is based on the NIO channels framework so that application requiring SCTP can take advantage of non-blocking multiplexed I/O. A new package, com.sun.nio.sctp, was defined to hold the new classes/interfaces. The package name is com.sun.nio.sctp, rather than something like java.nio.channels.sctp.
 
This distinction means that the API and implementation are fully supported and publicly accessible, but are not part of the Java SE platform. Once there is more experience in the industry with SCTP, then a standard API can be defined.
 
The main classes within this package are the three new channel types. These new channels can be split into two logical groups.
  1. The first logical group has similar semantics to TCP, SctpChannel and SctpServerChannel. An SctpChannel can control only a single association, that is, sending and receiving data to and from a single endpoint. SctpServerChannel listens and accepts new associations initiated on its socket address.
  2. The second logical group consists of just SctpMultiChannel. Instances of this channel type can control multiple associations, therefore can send and receive data to and from many different endpoints.

The SCTP stack is event driven, and applications can receive notifications of certain SCTP events. These events are most useful with SctpMultiChannel; since it can control multiple associations, you need to track the status of these notifications. For example, AssociationChangeNotification lets you know when new associations are started or terminated. If the association supports dynamic address configuration, then PeerAddressChangeNotification lets you know about IP addresses that have been added or removed from the peer endpoint. MessageInfo allows you to provide ancillary data for the message either being sent or received.

Multi-Streaming Example

This example demonstrates the multi-streaming feature of SCTP. The server implements a type of daytime protocol. It sends the current time date formatted in US English on one stream and in French on another.
Error handling is omitted to make the code more readable.
 
Multilingual DayTime Server

public class DaytimeServer {
    static int SERVER_PORT = 3456;
    static int US_STREAM = 0;
    static int FR_STREAM = 1;
    static SimpleDateFormat USformatter = new SimpleDateFormat(
                                "h:mm:ss a EEE d MMM yy, zzzz", Locale.US);
    static SimpleDateFormat FRformatter = new SimpleDateFormat(
                                "h:mm:ss a EEE d MMM yy, zzzz", Locale.FRENCH);
    public static void main(String[] args) throws IOException {
        SctpServerChannel ssc = SctpServerChannel.open();
        InetSocketAddress serverAddr = new InetSocketAddress(SERVER_PORT);
        ssc.bind(serverAddr);
        ByteBuffer buf = ByteBuffer.allocateDirect(60);
        CharBuffer cbuf = CharBuffer.allocate(60);
        Charset charset = Charset.forName("ISO-8859-1");
        CharsetEncoder encoder = charset.newEncoder();
        while (true) {
            SctpChannel sc = ssc.accept();
            /* get the current date */
            Date today = new Date();
            cbuf.put(USformatter.format(today)).flip();
            encoder.encode(cbuf, buf, true);
            buf.flip();
            /* send the message on the US stream */
            MessageInfo messageInfo = MessageInfo.createOutgoing(null,
                                                                 US_STREAM);
            sc.send(buf, messageInfo);
            /* update the buffer with French format */
            cbuf.clear();
            cbuf.put(FRformatter.format(today)).flip();
            buf.clear();
            encoder.encode(cbuf, buf, true);
            buf.flip();
            /* send the message on the French stream */
            messageInfo.streamNumber(FR_STREAM);
            sc.send(buf, messageInfo);
            cbuf.clear();
            buf.clear();
            sc.close();
        }
    }
}
      
Multilingual DayTime Client

public class DaytimeClient {
    static int SERVER_PORT = 3456;
    static int US_STREAM = 0;
    static int FR_STREAM = 1;
    public static void main(String[] args) throws IOException {
        InetSocketAddress serverAddr = new InetSocketAddress("localhost",
                                                             SERVER_PORT);
        ByteBuffer buf = ByteBuffer.allocateDirect(60);
        Charset charset = Charset.forName("ISO-8859-1");
        CharsetDecoder decoder = charset.newDecoder();
        SctpChannel sc = SctpChannel.open(serverAddr, 0, 0);
        /* handler to keep track of association setup and termination */
        AssociationHandler assocHandler = new AssociationHandler();
         /* expect two messages and two notifications */
        MessageInfo messageInfo = null;
        do {
            messageInfo = sc.receive(buf, System.out, assocHandler);
            buf.flip();
            if (buf.remaining() > 0 &&
                messageInfo.streamNumber() == US_STREAM) {
                System.out.println("(US) " + decoder.decode(buf).toString());
            } else if (buf.remaining() > 0 &&
                       messageInfo.streamNumber() == FR_STREAM) {
                System.out.println("(FR) " +  decoder.decode(buf).toString());
            }
            buf.clear();
        } while (messageInfo != null);
        sc.close();
    }
    static class AssociationHandler
        extends AbstractNotificationHandler<printstream>
    {
        public HandlerResult handleNotification(AssociationChangeNotification not,
                                                PrintStream stream) {
            if (not.event().equals(COMM_UP)) {
                int outbound = not.association().maxOutboundStreams();
                int inbound = not.association().maxInboundStreams();
                stream.printf("New association setup with %d outbound streams" +
                              ", and %d inbound streams.\n", outbound, inbound);
            }
            return HandlerResult.CONTINUE;
        }
        public HandlerResult handleNotification(ShutdownNotification not,
                                                PrintStream stream) {
            stream.printf("The association has been shutdown.\n");
            return HandlerResult.RETURN;
        }
    }
}


Sample Output

Following is an example of the output you might get:
>: java DaytimeClient
New association setup with 32 outbound streams, and 32 inbound streams.
(US) 4:00:51 PM Fri 15 May 09, British Summer Time
(FR) 4:00:51 PM ven. 15 mai 09, Heure d'ete britannique
The association has been shutdown.

Java SE 7 - Underscores in Numeric Literals

Underscores in Numeric Literals


In Java SE 7 and later, any number of underscore characters (_) can appear anywhere between digits in a numerical literal. This feature enables you, for example, to separate groups of digits in numeric literals, which can improve the readability of your code.
 
For instance, if your code contains numbers with many digits, you can use an underscore character to separate digits in groups of three, similar to how you would use a punctuation mark like a comma, or a space, as a separator.
 
The following example shows other ways you can use the underscore in numeric literals:
 
long creditCardNumber = 1234_5678_9012_3456L;
long socialSecurityNumber = 999_99_9999L;
float pi =  3.14_15F;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xCAFE_BABE;
long maxLong = 0x7fff_ffff_ffff_ffffL;
byte nybbles = 0b0010_0101;
long bytes = 0b11010010_01101001_10010100_10010010;
 
You can place underscores only between digits; you cannot place underscores in the following places:
  • At the beginning or end of a number
  • Adjacent to a decimal point in a floating point literal
  • Prior to an F or L suffix
  • In positions where a string of digits is expected


The following examples demonstrate valid and invalid underscore placements (which are highlighted) in numeric literals:
 
float pi1 = 3_.1415F;      // Invalid; cannot put underscores adjacent to a decimal point
float pi2 = 3._1415F;      // Invalid; cannot put underscores adjacent to a decimal point
long socialSecurityNumber1
  = 999_99_9999_L;         // Invalid; cannot put underscores prior to an L suffix
int x1 = _52;              // This is an identifier, not a numeric literal
int x2 = 5_2;              // OK (decimal literal)
int x3 = 52_;              // Invalid; cannot put underscores at the end of a literal
int x4 = 5_______2;        // OK (decimal literal)
int x5 = 0_x52;            // Invalid; cannot put underscores in the 0x radix prefix
int x6 = 0x_52;            // Invalid; cannot put underscores at the beginning of a number
int x7 = 0x5_2;            // OK (hexadecimal literal)
int x8 = 0x52_;            // Invalid; cannot put underscores at the end of a number
int x9 = 0_52;             // OK (octal literal)
int x10 = 05_2;            // OK (octal literal)
int x11 = 052_;            // Invalid; cannot put underscores at the end of a number
 

Java SE 7 - The try-with-resources Statement

The try-with-resources Statement
The try-with-resources statement is a try statement that declares one or more resources. A resource is as an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements the java.lang.AutoCloseable interface can be used as a resource.
 
The following example reads the first line from a file. It uses an instance of BufferedReader to read data from the file. BufferedReader is a resource that must be closed after the program is finished with it:
 
static String readFirstLineFromFile(String path) throws IOException {
  try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
  }
}
 
In this example, the resource declared in the try-with-resources statement is a BufferedReader. The declaration statement appears within parentheses immediately after the try keyword. The class BufferedReader, in Java SE 7 and later, implements the interface java.lang.AutoCloseable. Because the BufferedReader instance is declared in a try-with-resource statement, it will be closed regardless of whether the try statement completes normally or abruptly (as a result of the method BufferedReader.readLine throwing an IOException).
 
Prior to Java SE 7, you can use a finally block to ensure that a resource is closed regardless of whether the whether the try statement completes normally or abruptly. The following example uses a finally block instead of a try-with-resources statement:
 
static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
  BufferedReader br = new BufferedReader(new FileReader(path));
  try {
    return br.readLine();
  } finally {
    if (br != null) br.close();
  }
}
 
However, in this example, if the methods readLine and close both throw exceptions, then the method readFirstLineFromFileWithFinallyBlock throws the exception thrown from the finally block; the exception thrown from the try block is suppressed. In contrast, in the example readFirstLineFromFile, if exceptions are thrown from both the try block and the try-with-resources statement, then the method readFirstLineFromFile throws the exception thrown from the try block; the exception thrown from the try-with-resources block is suppressed. In Java SE 7 and later, you can retrieve suppressed exceptions; see the section Suppressed Exceptions for more information.
 
You may declare one or more resources in a try-with-resources statement. The following example retrieves the names of the files packaged in the zip file zipFileName and creates a text file that contains the names of these files:
 
  public static void writeToFileZipFileContents(String zipFileName, String outputFileName)
    throws java.io.IOException {
    java.nio.charset.Charset charset = java.nio.charset.Charset.forName("US-ASCII");
    java.nio.file.Path outputFilePath = java.nio.file.Paths.get(outputFileName);
    // Open zip file and create output file with try-with-resources statement
    try (
      java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);
      java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
    )
{
      // Enumerate each entry
      for (java.util.Enumeration entries = zf.entries(); entries.hasMoreElements();) {
        // Get the entry name and write it to the output file
        String newLine = System.getProperty("line.separator");
        String zipEntryName = ((java.util.zip.ZipEntry)entries.nextElement()).getName() + newLine;
        writer.write(zipEntryName, 0, zipEntryName.length());
      }
    }
  }
 
In this example, the try-with-resources statement contains two declarations that are separated by a semicolon: ZipFile and BufferedWriter. When the block of code that directly follows it terminates, either normally or because of an exception, the close methods of the BufferedWriter and ZipFile objects are automatically called in this order. Note that the close methods of resources are called in the opposite order of their creation.
 
The following example uses a try-with-resources statement to automatically close a java.sql.Statement object:
 
  public static void viewTable(Connection con) throws SQLException {
    String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";
    try (Statement stmt = con.createStatement()) {
      ResultSet rs = stmt.executeQuery(query);
      while (rs.next()) {
        String coffeeName = rs.getString("COF_NAME");
        int supplierID = rs.getInt("SUP_ID");
        float price = rs.getFloat("PRICE");
        int sales = rs.getInt("SALES");
        int total = rs.getInt("TOTAL");
        System.out.println(coffeeName + ", " + supplierID + ", " + price +
                           ", " + sales + ", " + total);
      }
    } catch (SQLException e) {
      JDBCTutorialUtilities.printSQLException(e);
    }
  }
 
The resource java.sql.Statement used in this example is part of the JDBC 4.1 and later API.
Note: A try-with-resources statement can have catch and finally blocks just like an ordinary try statement. In a try-with-resources statement, any catch or finally block is run after the resources declared have been closed.
 
Suppressed Exceptions
An exception can be thrown from the block of code associated with the try-with-resources statement. In the example writeToFileZipFileContents, an exception can be thrown from the try block, and up to two exceptions can be thrown from the try-with-resources statement when it tries to close the ZipFile and BufferedWriter objects. If an exception is thrown from the try block and one or more exceptions are thrown from the try-with-resources statement, then those exceptions thrown from the try-with-resources statement are suppressed, and the exception thrown by the block is the one that is thrown by the writeToFileZipFileContents method. You can retrieve these suppressed exceptions by calling the Throwable.getSuppressed method from the exception thrown by the try block.
 

Java SE 7 - Handling More Than One Type of Exception

In Java SE 7 and later, a single catch block can handle more than one type of exception. This feature can reduce code duplication and lessen the temptation to catch an overly broad exception.
 
Consider the following example, which contains duplicate code in each of the catch blocks:
 
catch (IOException ex) {
     logger.log(ex);
     throw ex;
catch (SQLException ex) {
     logger.log(ex);
     throw ex;
}
 
In releases prior to Java SE 7, it is difficult to create a common method to eliminate the duplicated code because the variable ex has different types.
 
The following example, which is valid in Java SE 7 and later, eliminates the duplicated code:
 
catch (IOException|SQLException ex) {
    logger.log(ex);
    throw ex;
}
 
The catch clause specifies the types of exceptions that the block can handle, and each exception type is separated with a vertical bar (|).
 
Note: If a catch block handles more than one exception type, then the catch parameter is implicitly final. In this example, the catch parameter ex is final and therefore you cannot assign any values to it within the catch block.
 
Bytecode generated by compiling a catch block that handles multiple exception types will be smaller (and thus superior) than compiling many catch blocks that handle only one exception type each. A catch block that handles multiple exception types creates no duplication in the bytecode generated by the compiler; the bytecode has no replication of exception handlers.

Java Applets, ASP.net - Can You Play Together?

Is your web application platform based on ASP.net technology? Would you like to leverage the Java platform's ubiquity to provide a rich user experience when users visit your web site? You can develop secure rich Internet applications (RIAs - applets and Java Web Start applications) by using the Java or the JavaFX language. Java client technology integrates seamlessly with ASP.net technology. In this article, we will explore various mechanisms by which Java applets can interact with ASP.net web pages.

Deploying an Applet in an ASP.net Page 

Use the Deployment Toolkit script to deploy an applet in an ASP.net page as shown in the following code snippet:

Default.aspx

<body>
    ...
    <script src="
http://www.java.com/js/deployJava.js"></script>
    <script>
        var attributes = { width:675, height:300} ;
        var parameters = { jnlp_href: 'applet/map-applet.jnlp'};
        deployJava.runApplet(attributes, parameters, '1.6');
    </script>
    ...
</body>
 
ASP.net, We Need To Talk 
 

An applet (running on the client) can interact with an ASP.net page (running on the server) by using the following mechanisms:


  • Cookies – An applet can set and retrieve cookies set by ASP.net pages.

  • Updating HTML elements and ASP.net controls – An applet can update the values of HTML elements and ASP.net controls in the parent web page by using the LiveConnect feature.

  • Directly invoking an ASP.net page – An applet can use the java.net.URLConnection class to invoke an ASP.net page, pass parameters to the page, and retrieve a response.

Modes of Interaction 
 

Cookies

Cookies can be used to share data between an applet and an ASP.net page. An applet can retrieve cookies set by an ASP.net page. By the same token, an ASP.net page can also retrieve cookies set by an applet.

In the code snippet shown next, the MapApplet class uses the java.net.CookieHandler class to retrieve the userName cookie set by the applet's parent web page. The text "Hello <user name>" is displayed on the top left corner of the applet.

private void getUserNameFromCookie() {
    try {
        // get the cookies that are applicable for this applet's parent web page
        URL docBaseUrl = this.getDocumentBase();
        
                   
CookieHandler cookieHandler = CookieHandler.getDefault();
        java.util.Map<String, List<String>> headers =
                        cookieHandler.get(docBaseUrl.toURI(),
                                        new HashMap<String,List<String>>());
        if (headers.isEmpty()) {
                  System.out.println("No cookies found!");
        } else {
                  getUserNameFromHeader(headers);
        }
    } catch(Exception e) {
        ...
    }
}

private void getUserNameFromHeader(java.util.Map<String, List<String>> headers) {
   for (String key : headers.keySet()) {
       for (String value : headers.get(key)) {
           if (key.equals("Cookie") && value.startsWith("userName")) {
               userName = value.split("=")[1];
           }
       }
   }
}

Note: You will need to sign your applet when using the java.net.CookieHandler API. If you do not wish to sign your applet, you can retrieve the value of a cookie by using JavaScript code in the ASP .net page. This value can be accessed by the applet in one of the following ways:


  • The value can be passed in as a parameter to the applet.

  • The applet can use the LiveConnect feature to interact with JavaScript code and access the value of the cookie.

Updating ASP.net Page With LiveConnect

An applet can interact with the JavaScript code in its parent web page by using the LiveConnect feature. The applet can invoke JavaScript functions and access JavaScript variables to update the contents of its parent web page. JavaScript code in the web page can also invoke applet methods.

In the following code snippet, the MapApplet class uses an instance of the netscape.javascript.JSObject class to update the contents of the asp:TextBox ID="addresses" control.

MapApplet.java

public void updateWebPage(String street, String city, String state) {
    char result = invokeAspPage(street, city, state);
    if (result == '1') {
        window.call("writeAddressOnPage", new Object[] {street, city, state});
    }
}
 

Default.aspx

<body>
    ...
    <script type="text/javascript" language="javascript">
        function 
                   
writeAddressOnPage(street, city, state) {
            var address = street + ", " + city + ", " + state;
            var form = document.getElementById("addrForm");
            var prevValue = form.elements["addresses"].value;
            form.elements["addresses"].value = prevValue + "\n" + address;
        }
    </script>

    <form id="addrForm" runat="server">
    <div>
        <p>Addresses saved to your address book:</p>
        <
                   
asp:TextBox ID="addresses" TextMode="MultiLine" Rows="6"
                            Columns="60" runat="server" ></asp:TextBox>
        </div>
    </form>
...
</body>
                   
 

When a form is posted, form field values become available to the next ASP.net page through the Request object. You might also choose to update hidden form fields with the applet's data.

Invoking an ASP.net Page

An applet can invoke an ASP.net page by using the java.net.URLConnection class. In the following code snippet, the MapApplet class opens a connection to the FileWriter.aspx page, passes parameters by using the connection's output stream, and receives a result by reading the connection's input stream.

MapApplet.java

public char invokeAspPage(String street, String city, String state) {
    char [] result = {'0'};
    ...
    String urlString = baseUrl + "FileWriter.aspx";
    URL url = new URL(urlString);
    URLConnection connection = url.openConnection();
    connection.setDoOutput(true);
    // send parameter to url connection
    OutputStreamWriter out = new OutputStreamWriter(
                          connection.getOutputStream());
    out.write("addresses=" + URLEncoder.encode(address, "UTF-8"));
    out.close();
    // read response from url connection
    BufferedReader in = new BufferedReader(
                            new InputStreamReader(
                            connection.getInputStream()));
    in.read(result);
    in.close();
    ...
    return result[0];
}
 

 

The FileWriter.aspx page writes the given address information to the userData/addresses.txt text file on the ASP.net server. The page returns a character value of '1' if the address is written successfully.

As shown in this article, there are a number of ways by which an applet can interact with an ASP.net page. Choose the option that works best for your application.

Friday, July 31, 2009

JVM Tuning

As a Java developer we come across various applications where Sun JVM is used in production environment. One of the most common and unresolved error in Production environment would be Java's "OutOfMemoryError". Application tries to do something which is memory intensive and suddenly JVM reports the error. Most of the guys would tell you to increase the heap size for the JVM. Unfortunately, Sun's JVM cannot be started with more 1GB of maximum heap space even if the system has enough memory available to allocate. Yes, it is quite surprising that even if system has 4GB RAM available but yet JVM cannot be allocated more than 1GB RAM. I recently ran into a similar issue where my application was deployed under Tomcat 5.5.23 and had maximum heap size set to 1GB. System had 4GB of RAM available. I increased maximum heap size from 1 GB to 2GB but then Tomcat never started. JVM was unable to create heap space! I did lot of search and finally taking clue from somewhere I switched my JVM from Sun's JVM to Oracle JRockit and now I was able to run Tomcat with 2GB of maximum heap space. It is quite shocking to know that Sun's JVM doesn't support more than 1GB of Max heap size and JRockit does.

Has Sun missed out on something?

- Jignesh Satra