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