Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6806822
Votes 6
Synopsis Font.getFontName() is slow in Java5 and 6
Category java:classes_2d
Reported Against
Release Fixed 7(b63)
State 10-Fix Delivered, bug
Priority: 3-Medium
Related Bugs
Submit Date 18-FEB-2009
Description
FULL PRODUCT VERSION :
Jre1.6.0_02,Jre1.6.0_06 Jre1.6.0_12

A DESCRIPTION OF THE PROBLEM :
Why is it that getFontName is slow in Java6?
I show below the measurement result in each JAVA version.
	Jre1.4.2_14(7.5ms)
	Jre1.6.0_02(247.6ms)
	Jre1.6.0_06(249.6ms)
	Jre1.6.0_12(224.7ms)

1. The OS is Windows Vista, but is there the report of such a phenomenon?

2. Will there be the plan improved in a future JAVA version?

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. I make applet for tests to measure time of getFontName.
2. I make HTML with above applet.
3. I carry out applet for tests in Jre1.4.2.
4. I carry out applet for tests in Jre1.6.0.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
In Jre1.4.2 and Jre1.6.0, a response of getFontName is equal.
ACTUAL -
I show below the measurement result in each JAVA version.
Jre1.4.2_14(7.5ms)
Jre1.6.0_02(247.6ms)
Jre1.6.0_06(249.6ms)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/*
 * test
 */

//    MyButton.java

import java.awt.*;
import java.awt.datatransfer.*;
import java.applet.Applet;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.security.AccessControlException;
import java.util.*;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.concurrent.TimeUnit;

public class MyButton extends Applet implements ActionListener {
   	long now,begin,diff;
        long mainnow,mainbegin,maindiff;
        long cnt1,cnt2,cnt3,cnt4,cnt5,cnt6,cnt7,cnt8,cnt9,cnt10,cnt11;
        Button button1;

    public void init() {
        button1 = new Button("OK");

        add(button1);

        button1.addActionListener(this);


        Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
        cnt6 = 0;
        for (int j = 1; j < 11; j++) {
                int i;
 		mainbegin = System.currentTimeMillis();
                System.out.println("" + j + " times run ");
        	for (i = 0; i < fonts.length; i++) {
    			begin = System.currentTimeMillis();
	        	String localFont = fonts[i].getFontName();
		       	now = System.currentTimeMillis();
		        diff = now - begin;
                        if (diff > 0 ) {
		            System.out.println("font serach (ms) =" + diff + "  fontname=" +localFont);
                        }
	         }
	         mainnow = System.currentTimeMillis();
	         maindiff = mainnow - mainbegin;
                 if ( j == 1){
                    cnt1 = maindiff;
                    cnt11 = cnt11 + cnt1;
                 }
                 if ( j == 2){
                    cnt2 = maindiff;
                    cnt11 = cnt11 + cnt2;
                 }
                 if ( j == 3){
                    cnt3 = maindiff;
                    cnt11 = cnt11 + cnt3;
                 }
                 if ( j == 4){
                    cnt4 = maindiff;
                    cnt11 = cnt11 + cnt4;
                 }
                 if ( j == 5){
                    cnt5 = maindiff;
                    cnt11 = cnt11 + cnt5;
                 }
                 if ( j == 6){
                    cnt6 = maindiff;
                    cnt11 = cnt11 + cnt6;
                 }
                 if ( j == 7){
                    cnt7 = maindiff;
                    cnt11 = cnt11 + cnt7;
                 }
                 if ( j == 8){
                    cnt8 = maindiff;
                    cnt11 = cnt11 + cnt8;
                 }
                 if ( j == 9){
                    cnt9 = maindiff;
                    cnt11 = cnt11 + cnt9;
                 }
                 if ( j == 10){
                    cnt10 = maindiff;
                    cnt11 = cnt11 + cnt10;
                 }
	}
        System.out.println("");
                    System.out.println("- 1 time (ms)=" + cnt1);
                    System.out.println("- 2 time (ms)=" + cnt2);
                    System.out.println("- 3 time (ms)=" + cnt3);
                    System.out.println("- 4 time (ms)=" + cnt4);
                    System.out.println("- 5 time (ms)=" + cnt5);
                    System.out.println("- 6 time (ms)=" + cnt6);
                    System.out.println("- 7 time (ms)=" + cnt7);
                    System.out.println("- 8 time (ms)=" + cnt8);
                    System.out.println("- 9 time (ms)=" + cnt9);
                    System.out.println("- 10 time (ms)=" + cnt10);
        System.out.println("");
        System.out.println("-- 10 times (ms) =" + cnt11);
        System.out.println("-- OS fonts count=" + fonts.length);
    }

    public void actionPerformed(ActionEvent evt) {
        System.out.println("Button is " + ((Button)evt.getSource()).getLabel());
    }
}
---------- END SOURCE ----------

Release Regression From : 1.4.2_15
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

Release Regression From : 1.4.2_15
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.
Posted Date : 2009-02-18 07:41:34.0
Work Around
N/A
Evaluation
Font.getFontName() may take a Locale parameter, and for TrueType fonts that means digging
into the name table to find if there's a localised name for that Locale.
Even if no locale is supplied the implementation (both now and in 1.4.2) has interpreted
that to mean the name for the current default locale, so implicitly the default
locale is used by getFontName(), ie Font.getFontName() invokes
Font.getFontName(Locale.getDefault());
in 1.4.2 the name table was cached in native allocated memory and native code iterates over it.
In 1.5 and 1.6 for robustness, we use Java NIO APIs to access the table,
and that table is not explicitly cached.
It appears that one had a negligible cost, and the other a measurable cost,
and I suspect the caching plays the major role.
Whilst I'm not sure how important this is for applications : ie how often
repeated calling of this API is used, it seems possible to improve this.
Rather than caching the table (these can be quite large) it would be more
effective (faster and smaller) to cache the localised name for the start up locale.
This should reduce the cost down to close to zero.
We could do this caching when first initialising the name table - presently
we cache only an English name, and don't even use it for this purpose.
This won't improve the performance of using NIO to read the name table,
but it minimises its use. Improving matters further is probably dependent on
some broader tuning of NIO and/or our use of it.
Font.getFamily() will have the same issue as getFontName() and both should
be addressed at the same time.
Posted Date : 2009-02-19 22:36:54.0
Comments
  
  Include a link with my name & email   

Submitted On 13-AUG-2009
Why is not the correction of this bug included in Java 6 update release?
Why Java 7 ?



PLEASE NOTE: JDK6 is formerly known as Project Mustang