内容简介:下面是问题代码的简化版本每次new Font()之后,调用g.drawString()方法都会在Non-Heap区域分配一块内存且不回收g.drawString()的调用栈如下,
下面是问题代码的简化版本
public class FontMain { public static void main(String[] args) throws IOException, FontFormatException, InterruptedException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { File file = new File("/Users/cayun/PingFang.ttc"); while (true) { run(file); Thread.sleep(1); } } private static void run(File file) throws IOException, FontFormatException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { BufferedImage blankImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB); Graphics2D g = blankImage.createGraphics(); Font font = Font.createFont(Font.TRUETYPE_FONT, file); font = font.deriveFont(12.0f); g.setFont(font); g.drawString("hello", 12, 12); } } 复制代码
泄漏原因
原因概述
每次new Font()之后,调用g.drawString()方法都会在Non-Heap区域分配一块内存且不回收
调用栈
g.drawString()的调用栈如下,
SunGraphics2D.drawString(String, int, int)
-> ValidatePipe.drawString(SunGraphics2D, String, double, double)
-> SunGraphics2D.getFontInfo()
-> SunGraphics2D.checkFontInfo
-> Font2D.getStrike(Font, AffineTransform, AffineTransform, int, int)
-> Font2D.getStrike(FontStrikeDesc, boolean)
-> FileFont.createStrike(FontStrikeDesc)
-> ... -> T2KFontScaler.<init>(Font2D, int, boolean, int)
-> T2KFontScaler.initNativeScaler(...)
根本原因
在调用栈中第二个标红的部分
new T2KFontScaler() 时会调用 T2KFontScaler.initNativeScaler()这个native方法,这个native方法会在Non-Heap部分分配内存,且之后也没有相应的回收机制。
demo代码&效果图
public class FontMain { public static void main(String[] args) throws IOException, FontFormatException, InterruptedException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, ClassNotFoundException, InstantiationException { File file = new File("/System/Library/Fonts/AquaKana.ttc"); Font font = Font.createFont(Font.TRUETYPE_FONT, file); font = font.deriveFont(12.0f); BufferedImage blankImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB); Graphics2D g = blankImage.createGraphics(); g.setFont(font); // T2KFontScaler无法通过new的方式创建,此处使用反射创建 Class clazz = Class.forName("sun.font.T2KFontScaler"); Constructor constructor = clazz.getConstructor(Font2D.class, int.class, boolean.class, int.class); constructor.setAccessible(true); while (true) { constructor.newInstance(((SunGraphics2D) g).getFontInfo().font2D, 0, true, 80005872); Thread.sleep(1); } } } 复制代码
辅助证明:JDK已知bug
JDK-7074159 : run out of memory
解决方案
为字体做个缓存
public class FontMain { private static Font font = null; private static Object lock = new Object(); public static void main(String[] args) throws IOException, FontFormatException, InterruptedException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { File file = new File("/Users/cayun/PingFang.ttc"); while (true) { run(file); Thread.sleep(1); } } private static void run(File file) throws IOException, FontFormatException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { BufferedImage blankImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB); Graphics2D g = blankImage.createGraphics(); if (font == null) { synchronized (lock) { if (font == null) { font = Font.createFont(Font.TRUETYPE_FONT, file); } } } font = font.deriveFont(12.0f); g.setFont(font); g.drawString("hello", 12, 12); } } 复制代码
原因详解
这个解决方法看起来有点奇怪,或许很容易就会有这样一个疑问:明明导致内存泄漏的是g.drawString()方法,却为何要对Font做缓存?
为了简单说明原因,我们先定义两种方案
- 方案1: 不使用缓存,就是原先会导致内存泄漏的方案
- 方案2: 对字体做缓存
以上所述就是小编给大家介绍的《记一次Font导致JVM堆外内存泄漏分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Hadoop 不需认证导致数据泄漏
- 苍翼之刃:论File Descriptor泄漏如何导致Crash?
- 一文带你了解如何排查内存泄漏导致的页面卡顿现象
- 每日一道面试题(第三期)---一般什么情况下会导致内存泄漏问题
- 我的程序跑了60多小时,就是为了让你看一眼JDK的BUG导致的内存泄漏。
- Android 系统开发_内存泄漏篇 -- "内存泄漏"的前世今生
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Introduction to Linear Optimization
Dimitris Bertsimas、John N. Tsitsiklis / Athena Scientific / 1997-02-01 / USD 89.00
"The true merit of this book, however, lies in its pedagogical qualities which are so impressive..." "Throughout the book, the authors make serious efforts to give geometric and intuitive explanations......一起来看看 《Introduction to Linear Optimization》 这本书的介绍吧!