FULL PRODUCT VERSION :
java version "1.6.0-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.6.0-beta-b59g)
Java HotSpot(TM) Client VM (build 1.6.0-beta-b59g, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
java.net.URLEncoder.encode should not create a bottleneck in muti-threaded applications. We noticed that there is a severe bottleneck in the JDK library which results in extermely poor performance of java.net.Encoder.encode in muti-threaded applications under load.
I realized that there was a problem in the test I wrote for the second run. What happens in this case is that java.net.URLEncoder and apache codec are running at the same time. Even though the example represents more real life, it doesn't do apple to apple comparison. I did the test again by increasing iTests value to to 50000 and keeping the loop as original test.
for(int i = 0; i < count; i++) {
es.submit(getCall());
start.countDown();
}
In this case, java.net.Encoder was 3.2 slower than apache.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the following code provided here. You will need org.apache.commons.codec library to run this.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The sun's library is as good as apache commons codec.
ACTUAL -
JDK's java.net.Encoder.encode is even 90 time slower for initial threads.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import org.apache.commons.codec.net.URLCodec;
import org.apache.commons.codec.EncoderException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class CodecTest {
//private static URLCodec s_codec = new URLCodec();
private static String s_encode = "This is a string for encoding!@#$%^&*()?<>;";
public CodecTest() {
}
private String encodeSun(String str) throws UnsupportedEncodingException {
return URLEncoder.encode(str, "UTF-8");
}
private String encodeApache(String str) throws EncoderException {
URLCodec s_codec = new URLCodec("UTF-8");
return s_codec.encode(str);
}
public void testSun(int iRuns) throws UnsupportedEncodingException {
for(int i = 0; i < iRuns; i++) {
encodeSun(s_encode + i);
}
}
public void testApache(int iRuns) throws UnsupportedEncodingException, EncoderException {
for(int i = 0; i < iRuns; i++) {
encodeApache(s_encode + i);
}
}
private static Callable getCall() {
return new Callable() {
public Object call() throws Exception {
CodecTest test = new CodecTest();
int iTests = 1000;
String sSun = null;
String sApache = null;
start.await();
//test sun
long lStart = System.nanoTime();
try {
test.testSun(iTests);
}
catch(UnsupportedEncodingException e) {
System.out.println("Unsupported encoding: " + e.getMessage());
}
long lEnd = System.nanoTime();
long lSunTime = lEnd - lStart;
barrier.await();
//test apache commons codec
lStart = System.nanoTime();
try {
test.testApache(iTests);
}
catch(UnsupportedEncodingException e) {
System.out.println("Unsupported encoding: " + e.getMessage());
}
lEnd = System.nanoTime();
long lApacheTime = lEnd - lStart;
synchronized(lock) {
System.out.println("Sun time: " + lSunTime / 1000000);
System.out.println("Apache commons codec time: " + lApacheTime / 1000000);
System.out.println("Apache commons codec is " + ((double) lSunTime / (double) lApacheTime) +
" times faster than Sun");
}
end.countDown();
return null;
}
};
}
public static final int count = 100;
public static final Object lock = new Object();
public static final CountDownLatch start = new CountDownLatch(count);
public static final CountDownLatch end = new CountDownLatch(count);
public static final CyclicBarrier barrier = new CyclicBarrier(count);
public static void main(String[] args) throws Exception {
ExecutorService es = Executors.newFixedThreadPool(count);
for(int i = 0; i < count; i++) {
es.submit(getCall());
start.countDown();
}
end.await();
es.shutdownNow();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use org.apache.commons.codec.net.URLCodec
java version "1.6.0-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.6.0-beta-b59g)
Java HotSpot(TM) Client VM (build 1.6.0-beta-b59g, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
java.net.URLEncoder.encode should not create a bottleneck in muti-threaded applications. We noticed that there is a severe bottleneck in the JDK library which results in extermely poor performance of java.net.Encoder.encode in muti-threaded applications under load.
I realized that there was a problem in the test I wrote for the second run. What happens in this case is that java.net.URLEncoder and apache codec are running at the same time. Even though the example represents more real life, it doesn't do apple to apple comparison. I did the test again by increasing iTests value to to 50000 and keeping the loop as original test.
for(int i = 0; i < count; i++) {
es.submit(getCall());
start.countDown();
}
In this case, java.net.Encoder was 3.2 slower than apache.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the following code provided here. You will need org.apache.commons.codec library to run this.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The sun's library is as good as apache commons codec.
ACTUAL -
JDK's java.net.Encoder.encode is even 90 time slower for initial threads.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import org.apache.commons.codec.net.URLCodec;
import org.apache.commons.codec.EncoderException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class CodecTest {
//private static URLCodec s_codec = new URLCodec();
private static String s_encode = "This is a string for encoding!@#$%^&*()?<>;";
public CodecTest() {
}
private String encodeSun(String str) throws UnsupportedEncodingException {
return URLEncoder.encode(str, "UTF-8");
}
private String encodeApache(String str) throws EncoderException {
URLCodec s_codec = new URLCodec("UTF-8");
return s_codec.encode(str);
}
public void testSun(int iRuns) throws UnsupportedEncodingException {
for(int i = 0; i < iRuns; i++) {
encodeSun(s_encode + i);
}
}
public void testApache(int iRuns) throws UnsupportedEncodingException, EncoderException {
for(int i = 0; i < iRuns; i++) {
encodeApache(s_encode + i);
}
}
private static Callable getCall() {
return new Callable() {
public Object call() throws Exception {
CodecTest test = new CodecTest();
int iTests = 1000;
String sSun = null;
String sApache = null;
start.await();
//test sun
long lStart = System.nanoTime();
try {
test.testSun(iTests);
}
catch(UnsupportedEncodingException e) {
System.out.println("Unsupported encoding: " + e.getMessage());
}
long lEnd = System.nanoTime();
long lSunTime = lEnd - lStart;
barrier.await();
//test apache commons codec
lStart = System.nanoTime();
try {
test.testApache(iTests);
}
catch(UnsupportedEncodingException e) {
System.out.println("Unsupported encoding: " + e.getMessage());
}
lEnd = System.nanoTime();
long lApacheTime = lEnd - lStart;
synchronized(lock) {
System.out.println("Sun time: " + lSunTime / 1000000);
System.out.println("Apache commons codec time: " + lApacheTime / 1000000);
System.out.println("Apache commons codec is " + ((double) lSunTime / (double) lApacheTime) +
" times faster than Sun");
}
end.countDown();
return null;
}
};
}
public static final int count = 100;
public static final Object lock = new Object();
public static final CountDownLatch start = new CountDownLatch(count);
public static final CountDownLatch end = new CountDownLatch(count);
public static final CyclicBarrier barrier = new CyclicBarrier(count);
public static void main(String[] args) throws Exception {
ExecutorService es = Executors.newFixedThreadPool(count);
for(int i = 0; i < count; i++) {
es.submit(getCall());
start.countDown();
}
end.await();
es.shutdownNow();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use org.apache.commons.codec.net.URLCodec
- relates to
-
JDK-6415062 30 MB memory trashed to get 30 kb string url encoded
- Resolved