United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4974531 : classes are loaded 512 bytes at a time, slowing down applet start time

Details
Type:
Bug
Submit Date:
2004-01-06
Status:
Resolved
Updated Date:
2005-02-02
Project Name:
JDK
Resolved Date:
2004-12-10
Component:
deploy
OS:
windows_xp
Sub-Component:
plugin
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.4.2
Fixed Versions:
1.4.2_08 (b01)

Related Reports
Backport:
Backport:
Relates:
Relates:

Sub Tasks

Description
Name: gm110360			Date: 01/06/2004


FULL PRODUCT VERSION :
java version "1.4.1_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_02-b06)
Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
using Microsoft Internet Explorer 6.0

A DESCRIPTION OF THE PROBLEM :
Starting up a Java application from a DOS command line takes significantly less time (30%) than when the same application is started as an applet, through a browser. Using FileMon trace, I found that in the case of an applet, the classes for the applet as well as the classes from rt.jar are loaded 512 bytes at a time. While in the case of an application, the disk access is done much more efficiently - the whole class is read in one disk access.

We have a large application here and starting it up as an applet takes in the order of 50 seconds, which is unacceptably slow. During that time, rt.jar is accessed in the order of 60,000 times, reading 512 bytes at a time. However, when starting the application from a DOS command line, rt.jar is accessed about 24,000 times and each access loads the full class.



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. pick any large java program.
2. create a JAR file for it and sign it.
3. embed the applet in a HTML file.
4. specify to use java plugin 1.4.1_02 instead of the browsers JVM by using <OBJECT> tag
5. start up a disk monitoring tool, such as FileMon.
6. using a browser, load the applet - NOTE # disk accesses
7. start the program as an apllication from a DOS command line - NOTE # disk accesses

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Starting the program as an applet should take about the same time as starting it as an application.
ACTUAL -
The applet takes 50 seconds to start, the application takes 30 seconds to start.

REPRODUCIBILITY :
This bug can be reproduced always.
(Incident Review ID: 223584) 
======================================================================

                                    

Comments
EVALUATION

Stanley was working with networking team on this issue. Reassign to Stanley.
###@###.### 2004-01-07

The problem is in sun/plugin/PluginURLJarFileCallBack.java. When retrieve() is called, the JAR file would be saved into the local temp file through BufferedOutputStream. However, the default buffer size of BufferedOuputStream is 512KB instead of the more efficient 8192KB, thus it degrade the performance. This problem has been fixed in Tiger already, but it should be backported to 1.4.2_0x. Reassign to CTE.
###@###.### 2004-02-10

For the applet case, there're actually 2 issues - the number of writes when cacheing the jar file and the number of reads when reading the jar file. The reading of jar file 512 bytes at a time is not limited to applet. Same problem can be observed when running a test applet such as SwingSet2 with appletviewer or as a standalone application (java -jar). 
The number of writes problem can be fixed in the java plugin CachedJarLoader by increasing the buffer size when instantiating io streams such as FileOutputStream. 
The number of reads problem can be fixed in the java/util/zip/ZipFile by increasing the buffer size when instantiating InflaterInputStream. However, initial assessment by TL team is that the change will cause performance degradation for small applications and shouldn't be made in an update release.
The number of reads problem still exists in Tiger. The increase in the default buffer size in BufferedInputStream and BufferedOutputStream in Tiger has no effect on the number of reads.
The number of writes problem seems to have been fixed in Tiger.
###@###.### 10/5/04 22:54 GMT
                                     
4-10-05 00:00:00
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
1.4.2_07


                                     
2004-08-26
SUGGESTED FIX

For reducing the number of writes:
------- CachedJarLoader.java -------
*** /tmp/sccs.Z_ay0E    Tue Oct  5 15:43:29 2004
--- CachedJarLoader.java        Thu Sep 16 14:19:08 2004
***************
*** 54,59 ****
--- 54,60 ----
  // Class to handle loading of jar files from the cache
  public class CachedJarLoader {
      
+     private static int BUF_SIZE = 8192;
      private URL url;
      private HttpURLConnection uc = null;
      private long lastModified = 0;
***************
*** 389,400 ****
          ZipInputStream in = null;
          ZipOutputStream out = null;
          try {
!             in = new ZipInputStream(new BufferedInputStream(uc.getInputStream()));
  
              // Open the output stream
              out = new ZipOutputStream(
                    new BufferedOutputStream(
!                   new FileOutputStream(dataFile)));
              out.setLevel(JarCache.compression);
              
              ZipEntry entry = in.getNextEntry();
--- 390,401 ----
          ZipInputStream in = null;
          ZipOutputStream out = null;
          try {
!             in = new ZipInputStream(new BufferedInputStream(uc.getInputStream(), BUF_SIZE));
  
              // Open the output stream
              out = new ZipOutputStream(
                    new BufferedOutputStream(
!                   new FileOutputStream(dataFile), BUF_SIZE));
              out.setLevel(JarCache.compression);
              
              ZipEntry entry = in.getNextEntry();
***************
*** 515,521 ****
            // Open the output stream
            out = new ObjectOutputStream(
                  new BufferedOutputStream(
!                 new FileOutputStream(raf.getFD())));
  
              manifest = jar.getManifest();
            //If no manifest, no need to worry about authentication
--- 516,522 ----
            // Open the output stream
            out = new ObjectOutputStream(
                  new BufferedOutputStream(
!                 new FileOutputStream(raf.getFD()), BUF_SIZE));
  
              manifest = jar.getManifest();
            //If no manifest, no need to worry about authentication
***************
*** 683,689 ****
              // Create an input stream
              in = new ObjectInputStream(
                   new BufferedInputStream(
!                  new FileInputStream(raf.getFD())));
              
              // Read the manifest
              int manifestLength = in.readInt();
--- 684,690 ----
              // Create an input stream
              in = new ObjectInputStream(
                   new BufferedInputStream(
!                  new FileInputStream(raf.getFD()), BUF_SIZE));
              
              // Read the manifest
              int manifestLength = in.readInt();


---
For reducing the number of reads:
------- ZipFile.java -------
*** /tmp/sccs.rDaq1E    Tue Oct  5 15:50:53 2004
--- ZipFile.java        Thu Sep 30 17:35:27 2004
***************
*** 207,213 ****
        case STORED:
            return zfin;
        case DEFLATED:
!           return new InflaterInputStream(zfin, getInflater()) {
                private boolean isClosed = false;
                  
                public void close() throws IOException {
--- 207,213 ----
        case STORED:
            return zfin;
        case DEFLATED:
!           return new InflaterInputStream(zfin, getInflater(), 8192) {
                private boolean isClosed = false;
                  
                public void close() throws IOException {
###@###.### 10/5/04 22:54 GMT
                                     
2004-10-05



Hardware and Software, Engineered to Work Together