发送连续网络摄像头图像时出现内存不足错误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 时出现网络错误