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

问题描述

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

TestClient:

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();
        }

    }
}

TestServer:

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,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);
}

解决方法

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

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

,

您在这里所做的是连续设置标签的图标:

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

此代码将执行以下操作:创建ImageIcon的新实例,将label链接到该实例,然后在出现新图像时,将丢失对原始对象的引用,并且垃圾回收器无法清除它或没有机会清除它,因为这是循环发生的,没有任何暂停。

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

您可以使用jvisualvm监视您的应用程序,然后看看。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...