发送连续网络摄像头图像时出现内存不足错误java

Posted

技术标签:

【中文标题】发送连续网络摄像头图像时出现内存不足错误java【英文标题】:out of memory error java while sending continous web cam images 【发布时间】:2021-01-21 06:43:18 【问题描述】:

我试图从客户端通过 ObjectOutStream 将网络摄像头(使用 Webcam-api)的连续图像发送到服务器,并将其显示在框架的标签上,并在 youtube 上找到代码,但程序在之后抛出内存不足错误一段时间。谁能解释它的原因?可能是服务器端的 inputStream 正在存储所有不需要的图像。如果是这样建议任何方法来清除服务器上的 InputStream。

测试客户端:

import java.io.IOException;

import java.awt.image.BufferedImage;
import java.io.*;
import java.net.*;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamResolution;

public class TestClient 


    static Socket socket;
    public static void main(String[] args) throws IOException,ClassNotFoundException
        Webcam webcam = Webcam.getDefault();
        webcam.setViewSize(WebcamResolution.VGA.getSize());
        System.out.println(WebcamResolution.VGA.getSize());
        webcam.open();

        socket = new Socket("localhost",5001);
        
        ObjectOutputStream dout = new ObjectOutputStream(socket.getOutputStream());
        JLabel label = new JLabel();
        JFrame frame = new JFrame("Client");

        frame.setSize(WebcamResolution.VGA.getSize());
        frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
        label.setSize(WebcamResolution.VGA.getSize());
        label.setVisible(true);

        frame.add(label);
        frame.setVisible(true);


        while(true) 
            BufferedImage wc = webcam.getImage();
            ImageIcon ic = new ImageIcon(wc);
            label.setIcon(ic);
            dout.writeObject(ic);
            dout.flush();
        

    

测试服务器:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.*;

public class TestServer 
    public static void main(String[] args) throws IOException,ClassNotFoundException
        ServerSocket server = new ServerSocket(5001);
        System.out.println("Waiting...");
        Socket socket = server.accept();
        System.out.println("Connected ..");
        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        JLabel label = new JLabel();
        JFrame frame = new JFrame("ServerSide");
        
        frame.setSize(640,480);
        frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
        label.setSize(640,480);
        label.setVisible(true);
        
        frame.add(label);
        frame.setVisible(true);
        
        while(true) 
            label.setIcon((ImageIcon)in.readObject());
        
            
    
    


一段时间后出错::

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.base/java.lang.reflect.Array.newArray(Native Method)
    at java.base/java.lang.reflect.Array.newInstance(Array.java:78)
    at java.base/java.io.ObjectInputStream.readArray(ObjectInputStream.java:2036)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1656)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:482)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:440)
    at java.desktop/javax.swing.ImageIcon.readObject(ImageIcon.java:501)
    at java.base/jdk.internal.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1175)
    at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2295)
    at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2166)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1668)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:482)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:440)
    at TestServer.main(TestServer.java:29)

编辑:: 我试过这个,但服务器只是第一次接收图像,之后它会引发空点异常。我不知道为什么?

客户:

DataOutputStream out = new DataOutputStream(socket.getOutputStream());
    
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while(true) 
   BufferedImage wc = webcam.getImage();
   ImageIO.write(wc, "jpg", bos); 
   byte imgBytes[] = bos.toByteArray();
   out.write(imgBytes,0,imgBytes.length);
   bos.flush();

服务器::

DataInputStream in=new DataInputStream(socket.getInputStream());
ImageInputStream imgin = ImageIO.createImageInputStream(in);

while(true)
    BufferedImage img=ImageIO.read(imgin);
    ImageIcon ic = new ImageIcon(img);
    label.setIcon(ic);

【问题讨论】:

尝试在任何循环中添加Thread.sleep(在客户端或服务器上),看看会发生什么 【参考方案1】:

InputStream 和 ObjectInputStream 都不能被“清除”,并且它们不会“存储”任何以前的结果。很可能线路上的位已损坏,并且正在发送的数据导致读取操作“意外”尝试分配一个巨大的数组。

请注意,通过 ObjectOutputStream 发送 ImageIcon 效率非常低;该协议浪费了大量的带宽,并浪费了大量的 CPU 周期来尝试序列化该对象,而这并不是为此而设计的。最好将您的图像保存为某种快速的图像格式(可能不是 PNG),然后发送,这样也可以更容易地调试损坏的发送。

【讨论】:

这不可能是真的:Most likely the bits on the wire are corrupted, and the data being sent is causing the read operation to try to allocate a gigantic array 'by accident'. 线上的位怎么会被破坏?如果是这样,互联网将永远无法工作。从 java 序列化/反序列化开始,到 TCP 协议等结束,都有特定的检查。几乎所有层都有一些检查以防止这种情况发生。 类之间的版本问题(serialVersionUID 然后覆盖对此的检查),例如。 但是版本问题会导致运行时异常,它们不会导致内存不足错误吗? 确实如此。例如,如果对象有不同版本但设置了 sVUID(一种常见做法),则会发生字段错位。【参考方案2】:

您在这里所做的是不断设置标签的图标:

while(true) 
            label.setIcon((ImageIcon)in.readObject());
        

这段代码的作用是创建ImageIcon 的新实例,将label 链接到该实例,然后,当新图像进入时,对原始对象的引用丢失并且垃圾收集器无法清除它或没有'没有机会清除它,因为这是在没有任何暂停的循环中发生的。

因此,如果相机每秒连续生成 60 帧,垃圾收集器将没有机会清除内存,因为(假设)每秒将在内存中创建 60 个对象。

您可以使用 jvisualvm 监控您的应用并查看情况。

【讨论】:

这些都不是真的。 in.readObject() 最终冻结了这个线程(因为,最终,你到达了阻塞的网络套接字),此时垃圾收集器将启动得很好。即使一个线程从不阻塞,它也会 GC 就好了;一旦你向虚拟机请求一个它不能给你的分配,它会(通常,这很复杂)首先进行 GC。 我并不是说它是 100% 正确的,但这是我的理论。如果有对象可供读取,它不会在套接字处停止。 您的理论基于对 VM 工作原理的误解。这不可能是真的。 我尝试添加 system.gc();在每个循环中它仍然崩溃。 .. 那是因为这个答案没有意义,@AAYUSHSHANDILYA

以上是关于发送连续网络摄像头图像时出现内存不足错误java的主要内容,如果未能解决你的问题,请参考以下文章

在 ListView 中使用 LazyList 时出现内存不足错误 [重复]

处理大型数据集时出现内存不足错误

尝试将图像发送到 React Native 中的预签名 URL 时出现网络错误

使用 Firebase 时出现内存不足错误

调用 createBitmap 时出现内存不足错误 [重复]

OpenCV:使用 cvWriteFrame 从网络摄像头写入视频时出现内存泄漏