首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >java中图像缩放的内存问题

java中图像缩放的内存问题
EN

Stack Overflow用户
提问于 2018-08-24 15:22:47
回答 1查看 120关注 0票数 0

环境:

JDK: 1.8u112 oracle

JRE: 10.0.2

JVM最大堆大小:~2 2GB。

操作系统: Windows 10

IDE: Netbeans 8.1

RAM: DDR4 8 8GB

处理器: 6700hq i7英特尔

Context

一个简单的GUI,它打开一个图像文件(jpg/png),并通过用户输入放大它。

描述

类扩展了JFrame。框架的contentPane有一个JButton、一个JLabel和一个JScrollPane。单击该按钮将显示一个JFileChooser。标签在滚动窗格内。选择一个文件将在标签中打开它(仅在此问题中打开图像文件-在其上测试jpg/png)。标签有一个鼠标滚轮监听器,可以通过Image.getScaledInstance缩放图像。每次缩放时,都会打印放大动作(新图像宽度(或高度)与相应原始图像宽度(或高度)的比率)和Runtime.totalMemory

Problem

  1. 放大图像时,代码似乎消耗了太多内存。对于7.23KB的png图像,任务管理器以11.8倍的放大倍数显示1708MB的内存使用量。预期应该在11.8*11.8*7.23KB
  2. Upon缩小的顺序附近,内存消耗不会减少
  3. 为什么堆首先要扩展这么多(大约17倍于mag,达到2 2GB)?丢弃的ImageIcon对象(参见代码)不会被gced吗?
  4. 如何使代码适用于mag中的mag * mag *originalImageSize(以字节为单位)<50%jvm最大堆大小?

代码

代码语言:javascript
复制
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                   
}

测试文件

除了test file之外,任何jpg或png图像都应该可以。

测试文件的输出

mag:110%内存:123MB内存:120%内存:123MB内存:130%内存:123MB内存:150%内存:123MB内存:160%内存:123MB内存:150%内存:123MB内存:160%内存:123MB内存:160MB内存:123MB内存:170%内存:123MB内存:180%内存:155MB内存:190%内存:155MB内存:200%内存:155MB内存:220%内存:155MB内存:230%内存:157MB内存:240%内存:157MB内存:250%内存:157MB内存:260%mem:157MB mag: 270%mem:253MB mag:280%mem:253MB mag:230%mem:253MB mag:300%mem:253MB mag:310%mem:256MB mag:330%mem:256MB mag:340%mem:256MB mag:350%mem:256MB mag:360%mem:256MB mag:370%mem:393MB mag:390%mem:393MB mag:390%mem:393MB mag:393MB mag:410%mem:393MB mag:420%mem:393MB mag:430%内存:466MB内存:440%内存:466MB内存:460%内存:466MB内存:470%内存:466MB内存:480%内存:466MB内存:489%内存:541MB内存:499%内存:541MB内存:509%内存:541MB内存:519%内存:541MB内存:529%内存:541MB内存:539%内存:641MB内存:549%内存:641MB内存:559%内存:641MB内存:569%mem:641MB内存:579%mem:641MB内存:589%mem:825MB内存:599% 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: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内存:759%内存:1029MB内存:769%内存:1104MB内存:779%内存:1104MB内存:789%内存:1104MB内存:799%内存:1104MB内存:809%内存:1075MB内存:819%内存:1075MB内存:829%内存:1075MB内存:839%内存:1182MB内存:1182MB内存:859%内存:1182MB内存:869%内存:1289MB内存:879%mem:1289MB内存:889%mem:154MB内存:899%mem:154MB内存:909%mem:152MB内存:919%mem:1569MB内存:929%内存:1569MB内存:939%内存:1569MB内存:949%内存:1480MB内存:959%内存:1480MB内存:969%内存:1548MB内存:979%内存:1548MB内存:989%内存:1655MB内存:999%内存:1655MB内存:1009%内存:1707MB内存:1019%内存:1707MB内存:1029%内存:1802MB内存:1039%内存:1850MB内存:1049%mem:1850MB内存:1059%mem:1871MB内存:1069%mem:1871MB内存:1079%mem:1801MB内存1862MB磁盘盒:1099%内存:1862MB磁盘盒:1109%mem:1815MB磁盘盒:1119%mem:1822MB磁盘盒:1129%mem:1758MB磁盘盒:1139%mem:1774MB磁盘盒:1149%mem:1711MB磁盘盒:1159%mem:1734MB磁盘盒:1169%mem:1676MB磁盘盒:1179%mem:1708MB磁盘盒:1189%mem:1654MB

EN

回答 1

Stack Overflow用户

发布于 2018-08-25 06:23:37

丢弃的ImageIcon对象(参见代码)不会被gced吗?

在GC不运行的情况下,如何对它们进行GC?

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

就这样。GC在需要的时候运行,通过将内存使用量保持在不必要的水平并不会带来太大的好处。

出于效率的原因,GC实际上是一个“幸存收集器”:它只处理幸存的对象,留下的是空闲内存。因此,运行它是有意义的,因为大多数对象在年轻时就会死亡。

预期的

应在11.8*11.8*7.23KB的量级左右

不,Java进程可以自由地使用您给它的所有内存。

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

是的,因为GC不需要运行。

为什么堆这么大(大约17倍于mag,达到2 2GB)

所有中等大小的图像都无法访问,但尚未收集。

在mag * mag *originalImageSize(以字节为单位)小于50%jvm最大堆大小的情况下,如何使代码适用于mag?

当Java进程需要内存时,它就会被回收。

我说了点小谎话。您可以手动调用System.gc,它可能会有所帮助。但不要这么做。虽然这回答了最后一个问题,但它并没有解决真正的问题。如果您想保持较低的内存使用率,那么可以使用-Xmx1000M或类似的方法来减少内存使用量。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51999393

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档