8209113: Use WeakReference for lastFontStrike for created Fonts

Reviewed-by: serb, jdv
This commit is contained in:
Phil Race 2019-12-05 13:24:52 -08:00
parent c96d36e1b0
commit 525b0422e4
3 changed files with 73 additions and 25 deletions

View File

@ -30,8 +30,10 @@ import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Locale;
import java.util.Set;
public abstract class Font2D {
@ -105,7 +107,22 @@ public abstract class Font2D {
* This pre-supposes that a FontStrike is a shareable object, which
* it should.
*/
protected Reference<FontStrike> lastFontStrike = new SoftReference<>(null);
protected Reference<FontStrike> lastFontStrike = new WeakReference<>(null);
/*
* if useWeak is true, proactively clear the cache after this
* many strikes are present. 0 means leave it alone.
*/
private int strikeCacheMax = 0;
/*
* Whether to use weak refs for this font, even if soft refs is the default.
*/
private boolean useWeak;
void setUseWeakRefs(boolean weak, int maxStrikes) {
this.useWeak = weak;
this.strikeCacheMax = weak && maxStrikes > 0 ? maxStrikes : 0;
}
/*
* POSSIBLE OPTIMISATION:
@ -304,6 +321,15 @@ public abstract class Font2D {
return getStrike(desc, false);
}
void updateLastStrikeRef(FontStrike strike) {
lastFontStrike.clear();
if (useWeak) {
lastFontStrike = new WeakReference<>(strike);
} else {
lastFontStrike = new SoftReference<>(strike);
}
}
FontStrike getStrike(FontStrikeDesc desc) {
return getStrike(desc, true);
}
@ -324,15 +350,13 @@ public abstract class Font2D {
*/
FontStrike strike = lastFontStrike.get();
if (strike != null && desc.equals(strike.desc)) {
//strike.lastlookupTime = System.currentTimeMillis();
return strike;
} else {
Reference<FontStrike> strikeRef = strikeCache.get(desc);
if (strikeRef != null) {
strike = strikeRef.get();
if (strike != null) {
//strike.lastlookupTime = System.currentTimeMillis();
lastFontStrike = new SoftReference<>(strike);
updateLastStrikeRef(strike);
StrikeCache.refStrike(strike);
return strike;
}
@ -366,31 +390,21 @@ public abstract class Font2D {
* which is what we want for what is likely a transient strike.
*/
int txType = desc.glyphTx.getType();
if (txType == AffineTransform.TYPE_GENERAL_TRANSFORM ||
if (useWeak ||
txType == AffineTransform.TYPE_GENERAL_TRANSFORM ||
(txType & AffineTransform.TYPE_GENERAL_ROTATION) != 0 &&
strikeCache.size() > 10) {
strikeRef = StrikeCache.getStrikeRef(strike, true);
} else {
strikeRef = StrikeCache.getStrikeRef(strike);
strikeRef = StrikeCache.getStrikeRef(strike, useWeak);
}
strikeCache.put(desc, strikeRef);
//strike.lastlookupTime = System.currentTimeMillis();
lastFontStrike = new SoftReference<>(strike);
updateLastStrikeRef(strike);
StrikeCache.refStrike(strike);
return strike;
}
}
void removeFromCache(FontStrikeDesc desc) {
Reference<FontStrike> ref = strikeCache.get(desc);
if (ref != null) {
Object o = ref.get();
if (o == null) {
strikeCache.remove(desc);
}
}
}
/**
* The length of the metrics array must be >= 8. This method will
* store the following elements in that array before returning:

View File

@ -25,6 +25,8 @@
package sun.font;
import java.lang.ref.Reference;
import java.util.concurrent.ConcurrentHashMap;
import sun.java2d.Disposer;
import sun.java2d.DisposerRecord;
@ -53,7 +55,7 @@ import sun.java2d.DisposerRecord;
class FontStrikeDisposer
implements DisposerRecord, Disposer.PollDisposable {
Font2D font2D;
ConcurrentHashMap<FontStrikeDesc, Reference<FontStrike>> strikeCache;
FontStrikeDesc desc;
long[] longGlyphImages;
int [] intGlyphImages;
@ -65,7 +67,7 @@ class FontStrikeDisposer
public FontStrikeDisposer(Font2D font2D, FontStrikeDesc desc,
long pContext, int[] images) {
this.font2D = font2D;
this.strikeCache = font2D.strikeCache;
this.desc = desc;
this.pScalerContext = pContext;
this.intGlyphImages = images;
@ -73,7 +75,7 @@ class FontStrikeDisposer
public FontStrikeDisposer(Font2D font2D, FontStrikeDesc desc,
long pContext, long[] images) {
this.font2D = font2D;
this.strikeCache = font2D.strikeCache;
this.desc = desc;
this.pScalerContext = pContext;
this.longGlyphImages = images;
@ -81,20 +83,26 @@ class FontStrikeDisposer
public FontStrikeDisposer(Font2D font2D, FontStrikeDesc desc,
long pContext) {
this.font2D = font2D;
this.strikeCache = font2D.strikeCache;
this.desc = desc;
this.pScalerContext = pContext;
}
public FontStrikeDisposer(Font2D font2D, FontStrikeDesc desc) {
this.font2D = font2D;
this.strikeCache = font2D.strikeCache;
this.desc = desc;
this.comp = true;
}
public synchronized void dispose() {
if (!disposed) {
font2D.removeFromCache(desc);
Reference<FontStrike> ref = strikeCache.get(desc);
if (ref != null) {
Object o = ref.get();
if (o == null) {
strikeCache.remove(desc);
}
}
StrikeCache.disposeStrike(this);
disposed = true;
}

View File

@ -256,6 +256,13 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
return t1Filter;
}
/* After we reach MAXSOFTREFCNT, use weak refs for created fonts.
* This means that a small number of created fonts as used in a UI app
* will not be eagerly collected, but an app that create many will
* have them collected more frequently to reclaim storage.
*/
private static int maxSoftRefCnt = 10;
static {
java.security.AccessController.doPrivileged(
@ -280,6 +287,9 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
System.getProperty("java.home","") + File.separator + "lib";
jreFontDirName = jreLibDirName + File.separator + "fonts";
maxSoftRefCnt =
Integer.getInteger("sun.java2d.font.maxSoftRefs", 10);
return null;
}
});
@ -2283,6 +2293,8 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
Thread fileCloser = null;
Vector<File> tmpFontFiles = null;
private int createdFontCount = 0;
public Font2D[] createFont2D(File fontFile, int fontFormat, boolean all,
boolean isCopy, CreatedFontTracker tracker)
throws FontFormatException {
@ -2293,10 +2305,21 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
FileFont font2D = null;
final File fFile = fontFile;
final CreatedFontTracker _tracker = tracker;
boolean weakRefs = false;
int maxStrikes = 0;
synchronized (this) {
if (createdFontCount < maxSoftRefCnt) {
createdFontCount++;
} else {
weakRefs = true;
maxStrikes = 10;
}
}
try {
switch (fontFormat) {
case Font.TRUETYPE_FONT:
font2D = new TrueTypeFont(fontFilePath, null, 0, true);
font2D.setUseWeakRefs(weakRefs, maxStrikes);
fList.add(font2D);
if (!all) {
break;
@ -2304,11 +2327,14 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
cnt = ((TrueTypeFont)font2D).getFontCount();
int index = 1;
while (index < cnt) {
fList.add(new TrueTypeFont(fontFilePath, null, index++, true));
font2D = new TrueTypeFont(fontFilePath, null, index++, true);
font2D.setUseWeakRefs(weakRefs, maxStrikes);
fList.add(font2D);
}
break;
case Font.TYPE1_FONT:
font2D = new Type1Font(fontFilePath, null, isCopy);
font2D.setUseWeakRefs(weakRefs, maxStrikes);
fList.add(font2D);
break;
default: