徹底解決Java處理圖片時,BufferedImage記憶體溢位的解決方案
阿新 • • 發佈:2019-02-11
最近系統總數無原因出現記憶體溢位問題,我程式內會讀取一張圖片,先壓縮圖片大小,然後轉成byte陣列寫入到資料庫
但是經過大量測試調查,在壓縮圖片時使用了Java的java.awt.image.BufferedImage總會佔用記憶體不釋放,造成記憶體疊加,最終記憶體溢位。
在各種百度,谷歌下解決無果,還得親自想辦法。
中間看到有人使用imagemagick解決記憶體溢位問題,主要是使用dos命令執行exe,達到壓縮圖片的目的
有興趣的可以研究下,我嘗試了下不是很好用,
於是我想到使用dos載入執行外部jar包,執行自己的程式碼。
我自己新建了一個工程,然後將自己的工具類單獨放到這個工程下,然後匯出打成jar包使用。
下載地址:http://pan.baidu.com/s/1i5OT6Kl
將PictureUtil.jar放到工程下,然後通過路徑找到PictureUtil.jar,
在dos命令下執行
Java -jar d:\PictureUtil.jar 2 "D:\1.jpg" 2000 2000 true "D:\22.jpg"
返回1是壓縮成功。
jar包還有其他功能如下,替換第1個引數2即可:
1、裁切圖片
2、壓縮圖片
3、新增水印
4、圖片黑白化操作
5、圖片透明化操作
6、格式轉化
dos下執行檢視引數說明
Java -jar d:\PictureUtil.jar 2 -h
java呼叫時如下:
package com.yunfeng.dj.common; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; /** * 此類在2017.11.03版本調整 使用執行外部jar實現圖片壓縮,以處理記憶體溢位的問題 基本原則是在dos下使用 java -jar * CompressPic.jar "C:/saveImg/" "1.jpg" "C:/saveImg/" "1.jpg" 2000 2000 * 以此不會影響本身的記憶體機制 * * @author dongqb */ public class CompressPic { /******************************************************************************* * 縮圖類(通用) 本java類能將jpg、bmp、png、gif圖片檔案,進行等比或非等比的大小轉換。 具體使用方法 * compressPic(大圖片路徑,生成小圖片路徑,大圖片檔名,生成小圖片文名,生成小圖片寬度,生成小圖片高度,是否等比縮放(預設為true)) */ private File file = null; // 檔案物件 private String inputDir; // 輸入圖路徑 private String outputDir; // 輸出圖路徑 private String inputFileName; // 輸入圖檔名 private String outputFileName; // 輸出圖檔名 private int outputWidth = 2000; // 預設輸出圖片寬 private int outputHeight = 2000; // 預設輸出圖片高 private String jarpatch = ""; public CompressPic() { // 初始化變數 String className = DBMainConfig.class.getName(); String classNamePath = className.replace(".", "/") + ".class"; URL is = DBMainConfig.class.getClassLoader().getResource(classNamePath); String path = is.getFile(); path = path.replace("%20", " "); path = path.substring(0, path.indexOf("WEB-INF") + 8); File f = new File(path); jarpatch = f.getParentFile().getAbsolutePath() + "\\CompressPic.jar"; } public boolean compress(String inputDir, String outputDir, String inputFileName, String outputFileName, int width, int height) { // 輸入圖路徑 this.inputDir = inputDir; // 輸出圖路徑 this.outputDir = outputDir; // 輸入圖檔名 this.inputFileName = inputFileName; // 輸出圖檔名 this.outputFileName = outputFileName; // 設定圖片長寬 this.outputWidth = width; this.outputHeight = height; return execute(); } // 圖片處理 private boolean execute() { StringBuffer cmd = new StringBuffer(); cmd.append("java -jar \"" + jarpatch + "\" "); cmd.append(" \"" + inputDir + "\""); cmd.append(" \"" + inputFileName + "\""); cmd.append(" \"" + outputDir + "\""); cmd.append(" \"" + outputFileName + "\""); cmd.append(" \"" + outputWidth + "\""); cmd.append(" \"" + outputHeight + "\""); Runtime rn = Runtime.getRuntime(); boolean flag = false; try { Process proc = rn.exec(cmd.toString()); InputStream stderr = proc.getInputStream(); // 獲取輸入流 InputStreamReader isr = new InputStreamReader(stderr); BufferedReader br = new BufferedReader(isr); String line = null; while ((line = br.readLine()) != null) { // 打印出命令執行的結果 if ("1".equals(line)) { flag = true; } } stderr.close(); br.close(); } catch (IOException e) { e.printStackTrace(); } return flag; } public static void main(String[] args) { while (true) { CompressPic pic = new CompressPic(); boolean flag = pic.compress("C://saveImg//", "C://saveImg//", "1.jpg", "3.jpg", 2000, 2000); System.out.println("壓縮完成,結果為:" + flag); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }