发送连续web cam图像时出现内存不足错误java

发送连续web cam图像时出现内存不足错误java,java,serversocket,objectinputstream,Java,Serversocket,Objectinputstream,我试图通过ObjectOutStream从客户端通过网络摄像头(使用网络摄像头api)向服务器发送连续图像,并将其显示在帧标签上,在youtube上找到一段代码,但该程序在一段时间后抛出内存不足错误。有人能解释一下原因吗?可能是服务器端的inputStream正在存储所有不需要的图像。若有,建议清除服务器上InputStream的任何方法 测试客户端: import java.io.IOException; import java.awt.image.BufferedImage; import

我试图通过ObjectOutStream从客户端通过网络摄像头(使用网络摄像头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);
}

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


请注意,通过ObjectOutputStream发送图像图标效率极低;该协议浪费了大量的带宽,并且在尝试序列化该对象时浪费了大量的CPU周期,而该对象不是为此而设计的。最好将图像保存为某种快速图像格式(虽然可能不是PNG),然后发送,这也会使调试损坏的发送变得更加容易。

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

while(true) {
            label.setIcon((ImageIcon)in.readObject());
        }
此代码的作用是:它将创建
ImageIcon
的新实例,将
label
链接到该实例,然后,当新图像进入时,对原始对象的引用将丢失,垃圾收集器无法清除该对象,或者没有机会清除它,因为这是在循环中发生的,没有任何暂停

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


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

这些都不是真的。in.readObject()最终冻结了这个线程(最终,您将进入网络套接字,它将阻塞),此时垃圾收集器将正常工作。即使线程从不阻塞,它也会很好;一旦你向虚拟机请求一个它不能给你的分配,它会(通常很复杂)首先进行GC。我不是说这是100%正确的,但这是我的理论。如果有可读取的对象,它不会在套接字处停止。你的理论是基于对VM如何工作的误解。这不可能是真的。我尝试添加system.gc();在每个循环中它仍然崩溃。。。这是因为这个答案毫无意义,@Aayusshandilyathat不可能是真的:
很可能是线路上的位被破坏了,而正在发送的数据正导致读取操作“意外地”尝试分配一个巨大的数组。
线路上的位怎么会被破坏?如果是那样的话,互联网就永远不会工作。有一些特定的检查,从java序列化/反序列化开始,到TCP协议结束,等等。几乎所有层都有一些适当的检查来防止这种情况发生。例如,类之间的版本问题(serialVersionUID然后覆盖此检查)。但是版本问题会导致运行时异常,它们不会导致内存不足错误,是吗?是的。与中一样,如果存在不同版本的对象,但设置了sVUID(一种常见做法),则会发生字段未对齐。请尝试在任何循环(在客户端或服务器上)中添加
线程。sleep
,然后查看发生了什么