【问题标题】:Is This Because of Memory Leakeage?这是因为内存泄漏吗?
【发布时间】:2021-10-18 07:36:17
【问题描述】:

我不断从本地服务器获取图像,我想在 JPanel 上显示它们。

我编写的代码可以运行一段时间而没有任何问题。但过了一段时间(大约 5 分钟),我得到了这个错误:

Exception in thread "Thread-0" java.lang.InternalError: a fault occurred in an unsafe memory access operation
        at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImage(Native Method)
        at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageR$
        at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.ja$
        at SICK.DisplayImage.updatePane(DisplayImage.java:225)
        at SICK.DisplayImage.access$000(DisplayImage.java:35)
        at SICK.DisplayImage$1.run(DisplayImage.java:356)
        at java.lang.Thread.run(Thread.java:748)

这是我从服务器读取图像的地方:

private BufferedImage updatePane(JLabel label) {

        try {
            InputStream input = new URL("http://192.168.250.21:8080/NewImage.jpg").openStream();
            
            ImageInputStream stream = ImageIO.createImageInputStream(input);
            
            ImageReader reader = ImageIO.getImageReaders(stream).next(); 

            reader.setInput(stream);

            int width = reader.getWidth(0);
            int height = reader.getHeight(0);
            ImageTypeSpecifier spec = reader.getImageTypes(0).next(); 

            BufferedImage image = MappedImageFactory.createCompatibleMappedImage(width, height, spec);
                    
            ImageReadParam param = reader.getDefaultReadParam();
            param.setDestination(image);

            image = reader.read(0, param);
            
            stream.close();
            input.close();

            initialize(image, label);
            return image;
        } catch (MalformedURLException e) {
            
            e.printStackTrace();
        } catch (IOException e) {
            
            e.printStackTrace();
        }
        return null;
    }

这是我将图像和 JLabel 添加到 JPanel 的初始化函数:

private void initialize(BufferedImage image, JLabel label) {
        GridBagConstraints c =  new GridBagConstraints(0,0,1,1,0,0, GridBagConstraints.NORTHWEST, GridBagConstraints.NORTHWEST, 
                    new Insets(0, 0, 0, 0), 0, 0);
                        
        JLabel imgLabel = new JLabel(new ImageIcon(image));
            
        int placeInY = 0;
        
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 0;
        c.weighty = 0;
        c.gridx = 0;
        c.gridy = placeInY++;
        c.gridheight = 1;
        c.gridwidth = 8;
        pane.add(imgLabel, c);
            
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 0;
        c.weighty = 0;
        c.gridx = 2;
        c.gridy = placeInY++;
        c.gridheight = 1;
        c.gridwidth = 1;
        pane.add(label, c);
        
        this.add(pane);
    }

这是我的主要功能:

public static void main(String[] args) {
        final DisplayImage page = new DisplayImage();

        final Thread t1 = new Thread(new Runnable() {
            
            public void run() {
                while(true) {
                
                    try {
                        TimeUnit.MILLISECONDS.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    page.removeAll();
                    page.updatePane(new JLabel("New Image"));
                    page.validate();
                    page.repaint();
                }
            }
        });
        
        SwingUtilities.invokeLater(new Runnable() {
            
            public void run() {
                t1.start();
            }
        });
    }

错误出现在image = reader.read(0, param);这一行

我查看了此错误消息,据说发生此错误的原因有几个。

其中之一是图像的来源可能无效,但我检查并服务器继续提供图像。

其中之一是 RAM 可能内存不足(内存泄漏)。我不确定,但这似乎更像它。

如果这个错误是由于内存泄漏引起的,我该如何解决?

注意:我正在使用此代码来传输图像:https://github.com/haraldk/TwelveMonkeys/blob/master/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedImageFactory.java

编辑:我在具有 512 MB RAM 的 linux 系统中遇到了这个问题。我尝试在具有 16 GB RAM 的 PC 上遇到此错误,但即使我等了 45 分钟,错误也没有发生。

我已经用 VisualVM 监控了 JVM 45 分钟。这是堆和元空间:

堆没有增加,但元空间不断增加。我还在看,而且还在增加。但元空间大小也会自动增加。

正如我读过的here,如果需要,元空间大小会自动增加。但在我看来;如果没有剩余未使用的 RAM 来增加大小,则可能导致内存泄漏错误。正如我上面提到的,我在拥有 512 MB RAM 的 Linux 系统上遇到了这个错误。

我认为,我必须等待更长的时间才能在我的 16 GB RAM 的 PC 上发生此错误。

你认为我对内存泄漏的看法是正确的吗?如果是这样,我该如何解决?

编辑 2:我检查了我的 Linux 系统中 JVM 的内存使用情况。以下是他们收到错误后的结果:

>sudo jcmd 1955 GC.heap_info
Java HotSpot(TM) Client VM warning: Insufficient space for shared memory file:
2616
Try using the -Djava.io.tmpdir= option to select an alternate temp location.

1955:
 def new generation   total 2560K, used 747K [0xac200000, 0xac4c0000, 0xaec00000)
  eden space 2304K,  32% used [0xac200000, 0xac2baf78, 0xac440000)
  from space 256K,   0% used [0xac440000, 0xac440000, 0xac480000)
  to   space 256K,   0% used [0xac480000, 0xac480000, 0xac4c0000)
 tenured generation   total 5504K, used 5210K [0xaec00000, 0xaf160000, 0xb4000000)
   the space 5504K,  94% used [0xaec00000, 0xaf1169d8, 0xaf116a00, 0xaf160000)
 Metaspace       used 7798K, capacity 7957K, committed 8088K, reserved 8496K

我无法将我的元空间大小降低到 10 MB 以下,因为它立即给出了下面的内存不足错误。因此,我在 PC 上使用以下命令将 Metaspace 降低到 13 MB,堆大小降低到 40MB:

java -jar -XX:MaxMetaspaceSize=13m -Xmx40m --illegal-access=warn gui.for.linux-0.0.1-SNAPSHOT.jar

但是当元空间已满时,我得到了这个错误:

Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "StreamCloser"

所以我无法通过降低我的 PC 上的堆和元空间大小来重现我在 Linux 系统上遇到的错误。

但是Linux系统中JVM的元空间在报错后被使用了94%。

我无法弄清楚导致错误发生的原因。

【问题讨论】:

  • The first answer to this question 谈到了这种InternalError。从我读到的代码有很多原因。
  • @JoachimSauer 我也读过那个答案。对不起,如果我听起来像我所说的那样,这个错误只能有两个原因。但我只是想指出我怀疑导致此错误的原因。
  • 内存可能是问题,但您必须监控您的应用程序才能确定。
  • @Hulk 我已经编辑并添加了 JVM 监控图像。你能检查一下吗?
  • 由于图像读取代码中会发生这种情况,您可以使用固定图像重现它,或者从磁盘加载它吗?

标签: java memory-leaks java-stream


【解决方案1】:

this post 中 Vyacheslav 的回答解释了元空间增加的原因。

我使用-Djava.compiler=NONE 选项运行应用程序,但元空间没有增加。

【讨论】:

    猜你喜欢
    • 2011-02-20
    • 2013-08-12
    • 1970-01-01
    • 2013-01-08
    • 2013-11-12
    • 2015-05-04
    相关资源
    最近更新 更多