记录一次压测爆出的IO异常:Can‘t create cache file

问题定位

根据抛出的异常提示,当时我第一时间使用df -h命令查看linux服务器的磁盘空间占用情况,结果发现空间几乎被占满的这些目录是Docker产生的,那很显然就是部署在Docker中的Java应用程序导致的问题了。

cd到被占满的目录中发现:

 全是上图展示的以+~JF开头的临时文件,当时的我感觉很疑惑这些到底是什么东西!

索性百度一下该临时文件名称,结果就是这一百度直接找到了解决思路!(面向百度编程甚好)

该临时文件的产生是因为使用了字体类——java.awt.Font,此类有一个静态方法:public static Font createFont(int fontFormat, InputStream fontStream),该方法的作用是使用指定的字体类型和字体的流数据返回一个新Font,该方法源码如下:

我在后续debug过程中,发现程序会进入createFont0方法中,createFont0方法就是会产生字体临时文件

该方法关键源码截图如下(该图中我标了一个我不太清楚作用的变量copiedFontData和四处关键代码逻辑):

 第一个方框中的代码作用:创建一个以+~JF打头的临时文件;

第二个方框中的代码作用:创建一个指向该临时文件的输出流;

第三个方框中的代码作用:向该临时文件中写入fontStream输入流,即createFont0的第二个参数——字体的输入流数据;

第四个方框中的代码作用:删除该临时文件。

不过此时注意copiedFontData参数,根据实际业务代码逻辑和源码逻辑,反正在我debug时此参数一直都为true(声明该参数为true的那行代码上有一大串注解,不过这个参数我没有深究作用,如果有晓得的大佬希望留言指导指导),所以if(!copiedFontData){...}中的代码根本不会走,即没有走第四个方框中的代码,没有删除刚刚创建的临时文件,到此导致系统抛出异常的根源找到了!!!

问题处理

其实当时处理问题的过程很简单,第一步肯定是先rm这些临时文件让系统正常运行,第二步就是修改代码。我们已经知道问题出在使用了传入参数是字体io流的createFont()方法导致,其实该Font类中还有一个传入参数是File的createFont()方法——public static Font createFont(int fontFormat, File fontFile),使用此方法即可。

查看此方法的源码

发现没有创建临时文件的代码逻辑。 

最后附上修改后的一小块代码逻辑(大致作用就是在filePath位置额外保存一份字体文件,直接使用该文件产生新Font,不细做解释,仅作为记录):

private static final String LOCAL_FONT_PATH = "font/simhei.ttf";
private static final Integer FONT_SIZE = 18;
private static final String LOCAL_FONT_FILE_NAME = "simhei.ttf";

public static Font getSimHeiFont(float fontSize) {
    String localPath = BaseConfig.getLocalPath();
    String filePath = localPath + File.separator + LOCAL_FONT_FILE_NAME;
    File file = new File(filePath);
    if (!file.exists()) {
        try {
            ClassPathResource classPathResource = new ClassPathResource(LOCAL_FONT_PATH);
            FileUtils.copyInputStreamToFile(classPathResource.getInputStream(), file);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    Font font = FontUtils.loadFont(file, fontSize);
    return font;
}

/**
 * 该方法会产生过多的临时文件
 */
@Deprecated
public static Font loadFont(InputStream inputStream, float fontSize) {
    try {
        Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, inputStream);
        Font dynamicFontPt = dynamicFont.deriveFont(fontSize);
        inputStream.close();
        return dynamicFontPt;
    } catch (Exception e) {
        e.printStackTrace();
        return new java.awt.Font("微软雅黑", Font.PLAIN, FONT_SIZE);
    }
}

public static Font loadFont(File file, float fontSize) {
    try {
        Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, file);
        return dynamicFont.deriveFont(fontSize);
    } catch (Exception e) {
        e.printStackTrace();
        return new java.awt.Font("微软雅黑", Font.PLAIN, FONT_SIZE);
    }
}

参考文章

https://www.cnblogs.com/zcy_soft/p/3503656.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值