linux上应用服务总是会突然JVM虚拟机崩溃直接挂掉(14天左右一次)。
代码如下:
**
* 生成最新的推荐图
*
* @param prdJson
* @param outPath
*/
private void generateRecommendImg(JSONObject prdJson, String outPath) throws Exception {
BufferedImage image = null;
try(FileInputStream imgFileInput = new FileInputStream(TOOL_FILE_SRC+"initTemplate.png");){
image = ImageIO.read(imgFileInput);
if (image == null) {
log.info("未找到初始模版-推荐图");
return;
}
} catch (FileNotFoundException e) {
log.error("文件输入流异常",e);
} catch (IOException e) {
log.error("IO异常",e);
}
int width = image.getWidth(null) == -1 ? 690 : image.getWidth(null);
int height = image.getHeight(null) == -1 ? 545 : image.getHeight(null)-1;
BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bimage.createGraphics();
//消除文字锯齿
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(image, 0, 0, null);
int iconWidth = ImgUtil.getIconWidth(WILL_SALEICON_FILE_SRC)+10;
//1、名称
ImgUtil.pressWordWatermark(prdJson.getString("tAShortName") + "-" + prdJson.getString("prdName"), g, new Color(39, 39, 46),
ImgUtil.getDefinedFont(PINGFANG_SC_FILE_SRC, Font.BOLD, 34), width, iconWidth, (float) (height * 0.15));
//2、周期
ImgUtil.pressWordWatermark(prdJson.getString("cycleDays"), g, new Color(39, 39, 46),
ImgUtil.getDefinedFont(PINGFANG_SC_FILE_SRC, Font.PLAIN, 26), width, null, (float) (height * 0.26));
//3、业绩指标值
Boolean isContainChinese = CheckUtils.isContainChinese(prdJson.getString("pfmTargetValue"));
if(isContainChinese){
ImgUtil.pressWordWatermark(prdJson.getString("pfmTargetValue"), g, new Color(247, 52, 52),
ImgUtil.getDefinedFont(PINGFANG_SC_FILE_SRC, Font.BOLD, 100), width, null, (float) (height * 0.5));
}else {
ImgUtil.pressWordWatermark(prdJson.getString("pfmTargetValue"), g, new Color(247, 52, 52),
ImgUtil.getDefinedFont(AVENIR_FILE_SRC, Font.BOLD, 100), width, null, (float) (height * 0.5));
}
//4、指标
ImgUtil.pressWordWatermark(prdJson.getString("pfmTargetName"), g, new Color(135, 135, 142),
ImgUtil.getDefinedFont(PINGFANG_SC_FILE_SRC, Font.PLAIN, 24), width, null, (float) (height * 0.628));
g.dispose();
try {
String formatName = outPath.substring(outPath.lastIndexOf(".") + 1);
ImageIO.write(bimage, formatName, new File(outPath));
} catch (Exception e) {
log.error("图片写入异常",e);
}
//获取图标前 名称 内容文字最后的X坐标
int conetTxtX = ImgUtil.getConetTailX(width, ImgUtil.getDefinedFont(PINGFANG_SC_FILE_SRC, Font.BOLD, 34),
prdJson.getString("tAShortName") + "-" + prdJson.getString(
"prdName"), iconWidth);
;
ImgUtil.pressImageWatermark(WILL_SALEICON_FILE_SRC, outPath, conetTxtX + 10, (int) (height * 0.096));
}
public static void pressWordWatermark(String content, Graphics2D g, Color color, Font font, int width, Integer otherWidth, float height) {
g.setColor(color);
//字体、字型、字号
g.setFont(font);
g.drawString(content, getWordWidth(width, font, content, otherWidth), height);
}
public final static void pressImageWatermark(String pressImg, String targetImg, int x, int y) {
try {
// 目标文件
File imageFile = new File(targetImg);
Image src = ImageIO.read(imageFile);
int wideth = src.getWidth(null);
int height = src.getHeight(null);
BufferedImage image = new BufferedImage(wideth, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
g.drawImage(src, 0, 0, wideth, height, null);
// 水印文件
File waterMarkImage = new File(pressImg);
Image markImage = ImageIO.read(waterMarkImage);
int weightMarkImage = markImage.getWidth(null);
int heightMarkImage = markImage.getHeight(null);
g.drawImage(markImage, x, y, weightMarkImage, heightMarkImage, null);
// 水印结束
g.dispose();
String formatName = targetImg.substring(targetImg.lastIndexOf(".") + 1);
ImageIO.write(image, formatName, new File(targetImg));
} catch (IOException e) {
log.error("图标水印处理异常",e);
}
}
/**
* 按照自定义字体文件创建font
* @param style
* @param fs
* @return
*/
public static Font getDefinedFont(String fontUrl,int style,float fs) {
Font definedFont = null;
try (InputStream is = new FileInputStream(new File(fontUrl));
BufferedInputStream bis = new BufferedInputStream(is);){
definedFont = Font.createFont(Font.TRUETYPE_FONT, is);
//设置字体大小,float型
definedFont = definedFont.deriveFont(style,fs);
} catch (FontFormatException e) {
log.error("",e);
} catch (IOException e) {
log.error("",e);
}
return definedFont;
}
/**
* 计算该字体字符串的长度,并定位到x坐标
*
* @param width 目标图片整个宽度
* @param font 格式
* @param content 文字
* @param otherWidth 其他宽度
* @return
*/
public static int getWordWidth(int width, Font font, String content, Integer otherWidth) {
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
int strWidth;
if (otherWidth == null) {
strWidth = 0;
} else {
strWidth = otherWidth;
}
for (int i = 0; i < content.length(); i++) {
strWidth += metrics.charWidth(content.charAt(i));
}
int x = (width - strWidth) / 2;
if (x > 0) {
return x;
}
return -x;
}
错误日志如下:
测试环境接口频度并不高,从上一次宕机到这次一共过去13天,昨天晚上到今天早上几乎没有请求,早上8点50分正在跑一个推荐图的定时任务,jvm直接崩溃。后面研究了下hs_err_pid文件觉得应该是调用JNI的报错,但程序中并没有用到,应该是引用的FontDesignMetrics有使用动态库.SO。从错误日志看起来是指针所对应的地址是无效地址,但找不到具体原因。