FULL PRODUCT VERSION :
java version "9.0.4" Java(TM) SE Runtime Environment (build 9.0.4+11) Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode) [same in 9.0.1]
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 10.0.16299.192] (also reproducible on Mac and Linux, but less pronounced)
EXTRA RELEVANT SYSTEM CONFIGURATION :
None (reproducible on different OSs and types of hardware)
A DESCRIPTION OF THE PROBLEM :
For most (not all) fonts java.awt.Font.layoutGlyphVector() has become significantly slower in Java 9 (compared to Java 8), up to a factor of 20.
After some quick profiling and looking through source code the apparent main cause is additional disc I/O,
i.e. Java 9 reads from actual font file for every call to "layoutGlyphVector" while Java 8 does not.
It seems that unlike previous versions Java 9 no longer caches all required data from TTF/OTF tables and instead rereads it every time (maybe due to more tables being used now and still only caching the old subset).
As there are a few fonts that are faster on Java 9, solving this issue could result not only in equal, but even better performance in Java 9,
which (especially when combined with the visual improvements in Java 9) could make GlyphVectors a viable component for performance sensitive text layout engines.
REGRESSION. Last worked in version 8u162
ADDITIONAL REGRESSION INFORMATION:
java version "1.8.0_162" Java(TM) SE Runtime Environment (build 1.8.0_162-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed mode) [same in previous Java 8 and similar in Java 7]
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the source code below, ideally using "arial" and "arial unicode ms". For these Java 9 should be about 5 and 15-20 (fifteen to twenty) times slower, respectively, than Java 8.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Java 9 should not be significantly slower. (As some fonts are faster it could even be generally faster when caching is fixed (if that is the cause))
ACTUAL -
Java 9 is significantly slower for most fonts.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
None (performance issue)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.io.File;
import java.util.Collections;
public class GVT {
//Adapt FONT_DIRECTORY for other OSs or specific folders with a selected sets of fonts ("Arial" and "Arial Unicode MS" highly recommended)
private static final String FONT_DIRECTORY = "c:\\windows\\fonts\\";
private static final int REPETITIONS = 5_000;
private static final char[] TEXT = "X sosofts 0,0 Steffieie Y".toCharArray();
private static final FontRenderContext FRC = new FontRenderContext(null, true, true);
public static void main(String[] args) throws Throwable {
System.out.println("Java " + System.getProperty("java.version") + " on " + System.getProperty("os.name") + "\n");
for (File fontFile : new File(FONT_DIRECTORY).listFiles()) {
if (fontFile.toString().toLowerCase().endsWith(".ttf")) {
Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile).deriveFont(123f)
.deriveFont(Collections.singletonMap(TextAttribute.KERNING, TextAttribute.KERNING_ON))
.deriveFont(Collections.singletonMap(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON));
System.out.print(fontFile.toString() + ";" + font.getName() + ";");
long start = System.nanoTime();
for (int i = 0; i < REPETITIONS; i++) {
font.layoutGlyphVector(FRC, TEXT, 0, TEXT.length, 0);
}
System.out.println((System.nanoTime() - start) / REPETITIONS / 1000);
}
}
}
}
---------- END SOURCE ----------