今天我在Java中摆弄了图像打开/缩放/显示,并编写了一些代码来打开图像文件,随机缩放并显示它很短的时间。
问题是:在显示100-1000次之后,我的“javaw.exe”的已用内存会增长和增长,甚至达到1 GB的内存空间。
我不知道我的代码中的内存泄漏在哪里,因为唯一的内存吃东西是我的照片而且只有2个(原始图像和缩放的那个,它总是分配给同一个变量(temp) )所以“老”的应该被GC挑选出来,也许你们可以看看它,非常简单。
1)您从硬盘驱动器中选择图像
2)随机缩放
3)它显示的时间很短,然后消失
4)转到2)
要缩放我使用此库的图像:http://www.thebuzzmedia.com/software/imgscalr-java-image-scaling-library/
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import org.imgscalr.Scalr;
public static void main(String[] args) throws IOException, InterruptedException {
JFileChooser chooser = new JFileChooser();
chooser.showOpenDialog(null);
BufferedImage originalImage = ImageIO.read(chooser.getSelectedFile());
BufferedImage temp;
while(true){
int width = (int) ((Math.random()*1000)+1);
int height = (int) ((Math.random()*1000)+1);
Thread.sleep(1000);
temp = Scalr.resize(originalImage,Scalr.Mode.FIT_EXACT, width, height);
showImage(temp, 800);
}
}
static void showImage(BufferedImage v,long length) throws InterruptedException {
JFrame frame = new JFrame();
frame.add(new JLabel(new ImageIcon(v)));
frame.setSize(v.getWidth(), v.getHeight());
frame.setVisible(true);
Thread.sleep(length);
frame.setVisible(false);
}
这是我第一次在这里发帖,所以如果我不清楚,请提出问题
提前感谢!
编辑:我监视了javaw.exe需要的内存
显示1张图片:75M 显示100张图片:330M 显示1000张图片:2,4G
编辑2:
我现在已经应用了你的有用建议,但我仍然有越来越多的内存,我的图像不再显示.. JFrames是空的。
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import org.imgscalr.Scalr;
public class App {
public static void main(String[] args) throws IOException, InterruptedException {
JFileChooser chooser = new JFileChooser();
chooser.showOpenDialog(null);
BufferedImage originalImage = ImageIO.read(chooser.getSelectedFile());
BufferedImage temp;
JFrame frame = new JFrame();
while(true){
int width = (int) ((Math.random()*1000)+1);
int height = (int) ((Math.random()*1000)+1);
Thread.sleep(1000);
temp = Scalr.resize(originalImage,Scalr.Mode.FIT_EXACT, width, height);
showImage(temp, 500, frame);
}
}
static void showImage(BufferedImage v,long length, JFrame frame) throws InterruptedException {
SwingUtilities.invokeLater(
() -> {
frame.removeAll();
frame.revalidate();
frame.repaint();
frame.add(new JLabel(new ImageIcon(v)));
frame.setSize(v.getWidth(), v.getHeight());
frame.setVisible(true);
try {
Thread.sleep(length);
} catch (Exception e) {}
frame.setVisible(false);
frame.dispose();
});
}
}
也许我把你的建议放在我的代码中的错误位置。
答案 0 :(得分:1)
您可能想尝试
originalImage.flush();
originalImage = null;
temp.flush();
temp = null;
但无法保证您的图片会被垃圾收集
除此之外,您还应考虑清除并重用相同的JFrame。
removeAll();//or remove the previous JLabel
revalidate();
repaint();
显示JFrame的正确方法是使用SwingUtilities invokeLater方法来确保这个" job"被放置在事件派遣线程(EDT)上。
// schedule this for the event dispatch thread (edt)
SwingUtilities.invokeLater(yourJFrame);
答案 1 :(得分:1)
下面的代码应该做你想要的。我使用了Timer而不是Thread.sleep。你在追加EDT。我也只是在容器中绘制图像。您应该使用JPanel(将其添加到JFrame并覆盖其paintComponent方法)。我还清理了一些方法。
import java.awt.image.BufferedImage;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Graphics;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import org.imgscalr.Scalr;
public class App extends JFrame implements ActionListener{
BufferedImage originalImage = null;
BufferedImage temp = null;
JFileChooser chooser = null;
public App(){
setVisible(true);
}
public static void main(String[] args) throws IOException, InterruptedException {
SwingUtilities.invokeLater(
() -> {
App app = new App();
Timer timer = new Timer(1000, app);
timer.start();
});
}
@Override
public void actionPerformed(ActionEvent ae){
if(null == chooser){
chooser = new JFileChooser();
chooser.showOpenDialog(this);
loadImage();
}
showImage();
repaint();
}
@Override
public void paint(Graphics g){
super.paint(g);
if(null == temp){
return;
}
g.drawImage(temp, 0, 0, null);
}
public void loadImage(){
try{
originalImage = ImageIO.read(chooser.getSelectedFile());
} catch(IOException ioe){
ioe.printStackTrace();
}
}
public void showImage() {
int width = (int) ((Math.random()*1000)+1);
int height = (int) ((Math.random()*1000)+1);
temp = Scalr.resize(originalImage,Scalr.Mode.BEST_FIT_BOTH, width, height);
setSize(width, height);
}
}