内存问题与Java的图像缩放(Memory issue with image zooming in

2019-10-30 01:27发布

ENV:

JDK:1.8u112神谕

JRE:10.0.2

JVM最大堆大小:〜2GB。

操作系统:Windows 10

IDE:Netbeans的8.1

内存:8GB DDR4

处理器:酷睿i7 6700hq英特尔

上下文

一个简单的GUI打开的图像文件(JPG / PNG)和经由用户输入放大它。

说明

一类扩展JFrame的。 该框架的contentPane中有一个JButton,一个JLabel和一个JScrollPane。 单击该按钮将显示一个JFileChooser。 标签是滚动窗格内。 选择一个文件(仅适用于测试这个问题,JPG / PNG的目的,打开图像文件)打开它的标签。 该标签具有的鼠标滚轮侦听使经由缩放图像的Image.getScaledInstance 。 在每个变焦,magnifiaction(新的图像宽度(或高度的比),对应的原始的)和Runtime.totalMemory被打印。

问题

  1. 在缩放到图像,太多的记忆,似乎正由代码所消耗。 任务管理器显示11.8倍的放大倍率1708 MB内存使用量为7.23KB PNG图像。 预计应该在11.8 * 11.8 * 7.23KB顺序
  2. 在缩小,内存消耗不会减少
  3. 为什么堆扩大这么多(大约〜17次MAG,达到2GB)摆在首位? 被丢弃ImageIcon对象(见代码)不是gced?
  4. 如何使代码可行的MAG,其中MAG美格* * originalImageSize(以字节为单位)<50%的最大JVM堆大小?

import java.awt.Dimension;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class gui extends javax.swing.JFrame {

Image image;
Dimension size;
private double mag = 1;
Runtime runtime = Runtime.getRuntime();

public gui() {
    initComponents();

}

private void zoom() {

    int[] newSize = {(int) (size.width * mag), (int) (size.height * mag)};

    if (newSize[0] > 0 && newSize[1] > 0) {
        label.setIcon(new ImageIcon(image.getScaledInstance(newSize[0], newSize[1], Image.SCALE_DEFAULT)));
    }

    System.out.println("mag:" + (int) (mag * 100) + "% mem:" + runtime.totalMemory() / 1024 / 1024 + "MB");

}

private void loadImage(File imgFile) throws IOException {

    String path = imgFile.getPath().toLowerCase();
    if (path.endsWith("gif")) {
        ImageIcon icon = new ImageIcon(path);

        image = icon.getImage();

        label.setIcon(icon);

    } else {
        image = ImageIO.read(imgFile);
        ImageIcon icon = new ImageIcon(image);
        label.setIcon(icon);
    }

    size = new Dimension(image.getWidth(null), image.getHeight(null));

}

@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">                          
private void initComponents() {

    dialog = new javax.swing.JFileChooser();
    jScrollPane1 = new javax.swing.JScrollPane();
    label = new javax.swing.JLabel();
    button = new javax.swing.JButton();

    dialog.setCurrentDirectory(new java.io.File("D:\\"));
        dialog.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                dialogActionPerformed(evt);
            }
        });

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Image Viewer");

        label.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        label.setVerticalAlignment(javax.swing.SwingConstants.TOP);
        label.addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                labelMouseWheelMoved(evt);
            }
        });
        jScrollPane1.setViewportView(label);

        button.setText("open");
        button.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 689, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(button)
                        .addGap(0, 0, Short.MAX_VALUE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(button)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 430, Short.MAX_VALUE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>                        

private void dialogActionPerformed(java.awt.event.ActionEvent evt) {                                       
    // TODO add your handling code here:

    if (evt.getActionCommand().equals(JFileChooser.APPROVE_SELECTION)) {

        try {
            File file = dialog.getSelectedFile();

            loadImage(file);

            setTitle(file.getPath());
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }

}                                      

private void labelMouseWheelMoved(java.awt.event.MouseWheelEvent evt) {                                      

    if (image != null) {
        int amt = -evt.getWheelRotation();
        double newMag = mag + amt * 0.1;

        if (newMag > 0) {
            mag = newMag;
            zoom();

        }

    }


}                                     

private void buttonActionPerformed(java.awt.event.ActionEvent evt) {                                       
    // TODO add your handling code here:
    dialog.showOpenDialog(this);
}                                      

public static void main(String args[]) throws Exception {

    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {

            new gui().setVisible(true);

        }
    });
}

// Variables declaration - do not modify                     
private javax.swing.JButton button;
private javax.swing.JFileChooser dialog;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JLabel label;
// End of variables declaration                   
}

测试文件

任何JPG或PNG图片应该做的,除了测试文件 。

从测试文件输出

MAG:110%MEM:123MB MAG:120%MEM:123MB MAG:130%MEM:123MB MAG:140%MEM:123MB MAG:150%MEM:123MB MAG:160%MEM:123MB MAG:150%MEM:123MB MAG :160%MEM:123MB MAG:170%MEM:123MB MAG:180%MEM:155MB MAG:190%MEM:155MB MAG:200%MEM:155MB MAG:210%MEM:155MB MAG:220%MEM:155MB MAG: 230%MEM:157MB MAG:240%MEM:157MB MAG:250%MEM:157MB MAG:260%MEM:157MB MAG:270%MEM:253MB MAG:280%MEM:253MB MAG:290%MEM:253MB MAG:300 %MEM:253MB MAG:310%MEM:253MB MAG:320%MEM:256MB MAG:330%MEM:256MB MAG:340%MEM:256MB MAG:350%MEM:256MB MAG:360%MEM:256MB MAG:370% MEM:393MB MAG:380%MEM:393MB MAG:390%MEM:393MB MAG:400%MEM:393MB MAG:410%MEM:393MB MAG:420%MEM:393MB MAG:430%MEM:466MB MAG:440%MEM :466MB MAG:450%MEM:466MB MAG:460%MEM:466MB MAG:470%MEM:466MB MAG:480%MEM:466MB MAG:489%MEM:541MB MAG:499%MEM:541MB MAG:509%MEM: 541MB MAG:519%MEM:541MB MAG:529%MEM:541MB MAG:539%MEM:641MB MAG:549%MEM:641MB MAG:559%MEM:641MB MAG:569%MEM:641MB MAG:579%MEM:641MB MAG:589%MEM:825MB MAG:599%MEM:825MB MAG:609%MEM :825MB MAG:619%MEM:825MB MAG:609%MEM:825MB MAG:619%MEM:825MB MAG:629%MEM:892MB MAG:639%MEM:892MB MAG:649%MEM:892MB MAG:659%MEM: 892MB MAG:669%MEM:892MB MAG:679%MEM:892MB MAG:689%MEM:881MB MAG:699%MEM:881MB MAG:709%MEM:881MB MAG:719%MEM:881MB MAG:729%MEM:1029MB MAG:739%MEM:1029MB MAG:749%MEM:1029MB MAG:759%MEM:1029MB MAG:769%MEM:1104MB MAG:779%MEM:1104MB MAG:789%M​​EM:1104MB MAG:799%MEM:1104MB MAG :809%MEM:1075MB MAG:819%MEM:1075MB MAG:829%MEM:1075MB MAG:839%MEM:1182MB MAG:849%MEM:1182MB MAG:859%MEM:1182MB MAG:869%MEM:1289MB MAG: 879%MEM:1289MB MAG:889%MEM:1542MB MAG:899%MEM:1542MB MAG:909%MEM:1542MB MAG:919%MEM:1569MB MAG:929%MEM:1569MB MAG:939%MEM:1569MB MAG:949 %MEM:1480MB MAG:959%MEM:1480MB MAG:969%MEM:1548MB MAG:979%MEM:1548MB MAG:989%MEM:1655MB MAG:999%MEM:1655MB MAG:1009%MEM:1707MB MAG:1019% MEM:1707MB MAG:1029%MEM:1802MB MAG:1039%MEM:1850MB MAG:1049%MEM:1850MB MAG:1059%MEM:1871MB MAG:1069%MEM:1871MB MAG:1079%MEM:1801MB MAG:1089%MEM :1862 MB MAG:1099%MEM:1862MB MAG:1109%MEM:1815MB MAG:1119%MEM:1822MB MAG:1129%MEM:1758MB MAG:1139%MEM:1774MB MAG:1149%MEM:1711MB MAG:1159%MEM:1734MB MAG:1169%MEM:1676MB MAG:1179%MEM:1708MB MAG:1189%MEM:1654MB

Answer 1:

被丢弃的ImageIcon对象(见代码)不是gced?

他们如何能不GC运行被GC'ed?

为什么要当内存足够的GC运行?

而已。 该GC在需要时运行,并没有太多的保留内存使用超过必要降低取胜。

出于效率的原因,GC实际上是一个“幸存者收藏家”:只幸存的对象涉及的,什么是留下的可用内存。 因此,它是有道理的,因为大多数对象死在年轻ALAP运行它。


预计应该在11.8 * 11.8 * 7.23KB顺序

不,一个Java程序是免费使用的,把你给它的内存。

在缩小,内存消耗不会减少

是的,没有必要为GC运行。

为什么堆扩大这么多(在MAG左右〜17倍,达到2GB)

在所有中间尺寸的图像是无法访问的,但还没有收集到。

如何使代码可行的MAG,其中MAG美格* * originalImageSize(以字节为单位)<50%的最大JVM堆大小?

你不能。 当内存会被Java进程是必要的,那么它就会被回收。


我躺在了一下。 你可以调用System.gc手动,它可能会有所帮助。 但不这样做。 虽然这个回答最后一个问题,它解决不了实际问题。 如果你想保留的内存使用量低,然后使用Java的给予较少的内存-Xmx1000M或相似。



文章来源: Memory issue with image zooming in java