1. 程式人生 > >徹底解決Java處理圖片時,BufferedImage記憶體溢位的解決方案

徹底解決Java處理圖片時,BufferedImage記憶體溢位的解決方案

最近系統總數無原因出現記憶體溢位問題,我程式內會讀取一張圖片,先壓縮圖片大小,然後轉成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();
			}
		}
	}
}