SyntaxHighlighter JS

Showing posts with label optimize. Show all posts
Showing posts with label optimize. Show all posts

2015-09-17

XMLGregorianCalendar DatatypeFactory considered harmful

If you have ever worked with XML and JAXB, you will be familiar with XmlGregorianCalendar.  It is the default Java class that JAXB uses to represent XML date/time.  

A Java web service application I worked on experienced performance issues under load.  By simulating heavy SOAP request traffic with LoadUI and profiling with YourKit, I discovered the culprit was DatatypeFactory.


This particular SOAP web service response had at least fifty date/time fields. The code to construct the JAXB response naively called 


    DatatypeFactory.newInstance().newXMLGregorianCalendar();

for each date/time field.


The call DatatypeFactory.newInstance() turns out to be very expensive. As shown in the JavaDoc

the newInstance method is a four step process with reflection.

Each time DatatypeFactory.newInstance() is called, Java has to rerun the four step discovery and creation process.


The obvious solution is to cache and reuse DatatypeFactory.newInstance(). I needed to confirm that the DatatypeFactory is thread-safe.  By doing a simple DatatypeFactory.newInstance().getClass().getName(), I discovered that the concrete implementation is com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl

By looking at the source code at http://www.docjar.com/html/api/com/sun/org/apache/xerces/internal/jaxp/datatype/DatatypeFactoryImpl.java.html, I verified that newXMLGregorianCalendar() is thread-safe.


The implementation at line 201 is just

public XMLGregorianCalendar newXMLGregorianCalendar() {
    return new XMLGregorianCalendarImpl();
}

which is about as thread-safe as you can get.

Moral of Story: Do not call DatatypeFactory.newInstance() every time you need an XMLGregorianCalendar


Additional source

2013-01-21

Java Gotchas: Boxed Primitive

Primitives are int, double, boolean, etc. Boxed primitives are the Object version of primitives, i.e. Integer, Double, BooleanAs a general rule, prefer using primitives over boxed primitives.

Gotchas
1.) Do not use the == operator to compare boxed primitives.
     

            Integer a = new Integer(7);
     Integer z = new Integer(7);

     System.out.println(a == z);

Prints out false because == is doing an identity comparison on the Integer   reference memory location.  Since object a and object z are two different objects in different areas of memory, the (a == z) test is false.

To do an equality test on boxed primitives, use the equals method.

           a.equals(z);

Or unbox the boxed primitive and then do the == test

     int x = a;
     int y = z;

     System.out.println(x == y);

2.) Do not unbox in a loop

     Long sum = 0L;
     for (long i = 0; i < Integer.MAX_VALUE; ++i) {
         sum += i;
     }

At code sum += i , the boxed primitive sum will be auto-unboxed to perform addition then a Long object created to assign to sum.  This caused time and space performance issues.

Fix the above code by changing sum to a primitive long.

3.) Boxed primitives can throw NullPointerException
   
     static Integer i;
           
     public static void main(String... args) {
         System.out.println(i == 42);
     }

The code i == 42 will throw a NullPointerException because when i gets auto-unboxed to do a comparison with primitive int 42, the variable i is null;

2013-01-20

Java Memory Leak: Obsolete reference

In program

public class Stack {
  private Object[] elements;
  private int size = 0;

  private static final int INIT_SIZE = 16;

  public Stack() {
    elements = new Object[INIT_SIZE];
  }

  public void push() {
    checkSize();
    elements[size++] = e;
  }

  public Object pop() {
    if (size == 0) { throws EmptyStackException(); }
    Object result = elements[--size];
    return result;

  }

  private void checkSize() {
    if (elements.length = size) {
        elements = Arrays.copyOf(elements, 2 * size + 1);
    }
  }
}

The code line
Object result = elements[--size];

is a Java memory leak because even though the size decrements, the obsolete reference to the Object at element[size] still exists in memory.

The fix is to null of the unneeded reference at elements

  public Object pop() {
    if (size == 0) { throws EmptyStackException(); }
    Object result = elements[--size];
    elements[size] = null;

    return result;
  }

Arrays and collections are places where memory leak obsolete references occur often.

2013-01-13

Optimize Java DNS Lookup

  • Prefer IPv4
    Starting with version 4, Java performs both IPv6 and IPv4 DNS lookups. If the DNS server is not set up to properly respond to IPv6 queries, then Java will wait for the IPv6 query to time out. This can manifest in what looks like network slowdowns.

    To bypass IPv6 DNS lookups, set the Java System property java.net.preferIPv4Stack to true.

    Command line:  -Djava.net.preferIPv4Stack=true 
    Java:
    System.setProperty("java.net.preferIPv4Stack",
      "true");

  • Increase cache time
    When a Java 6 security manager is not set, the default DNS cache is 30 seconds.  To reduce network DNS queries, the number of seconds of DNS cache can be increased by setting the networkaddress.cache.ttl System property.  Set this property to -1 to never expire the DNS cache.


    Command line:  -Dnetworkaddress.cache.ttl=-1
    Java:  
    System.setProperty("networkaddress.cache.ttl",
      "-1");