我正在使用sarxos http://webcam-capture.sarxos.pl/
的Webcam capture API
我编写此代码以不断从网络摄像头获取图像并通过套接字将其发送到服务器。
客户端代码
public static void main(String[] args) throws IOException
{
Socket socket = new Socket("127.0.0.1", 54339);
ObjectOutputStream sender = new ObjectOutputStream(socket.getOutputStream());
Webcam wCam = Webcam.getDefault();
wCam.setViewSize(WebcamResolution.VGA.getSize());
wCam.open();
while (true)
{
sender.writeObject(new ImageIcon(wCam.getImage()));
}
}
服务器代码
public static void main(String[] args) throws IOException
{
ServerSocket server = new ServerSocket(54339);
Socket socket = server.accept();
ObjectInputStream rcv = new ObjectInputStream(socket.getInputStream());
while (true)
{
rcv.readObject();
System.out.println("receive");
}
}
但是大约2到3分钟之后,我的客户端内存不足而卡住了,因为它需要太多内存。
我认为这是因为这一行new ImageIcon(wCam.getImage())
但我不知道如何修复它。
我已经尝试了sender.flush()
,但这不起作用
答案 0 :(得分:1)
基本上ObjectOutputStream.writeObject()
和ObjectInputStream.readObject()
会为他们发送/接收的对象维护一个 hard
references
的表格。当ObjectOutputStream
对象重新发送时,仅发送对象的句柄,而ObjectInputStream
将接收到的句柄转换为先前接收的对象的引用。此功能可以减少带宽和内存使用量,但仅限于定期重新发送对象的程序。由于ObjectInputStream/ObjectOutputStream
硬引用这些对象,Garbage Collector
无法收集它们,最终这些对象成为内存泄漏。
为了避免这种情况,Java提供ObjectOutputStream.writeUnshared()
和ObjectInputStream.readUnshared()
方法,但这些方法也有已知的内存泄漏问题,请查看JDK-6525563 : Memory leak in ObjectOutputStream以获取有关该方法的更多信息问题。
所以你有两个选择;
read/writeUnshared()
代替read/writeObject()
,并且每隔一段时间调用ObjectOutputStream
的{{1}}方法,以释放reset()
泄露的内存, ObjectOutputStream
。您可以像这样ObjectInput/OutputStream
读/写BufferedImage
; 写作:
DataInput/OutputStream
读:
try (DataOutputStream sender = new DataOutputStream(new BufferedOutputStream(new Socket("127.0.0.1", 54339).getOutputStream()))) //never use DataStreams without buffering, too slow
{
while (true)
{
BufferedImage frame = wCam.getImage(); //get frame from webcam
int frameWidth = frame.getWidth();
int frameHeight = frame.getHeight();
sender.writeInt(frameWidth); //write image with
sender.writeInt(frameHeight); //write image height
int[] pixelData = new int[frameWidth * frameHeight];
frame.getRGB(0, 0, frameWidth, frameHeight, pixelData, 0, frameWidth);
for (int i = 0; i < pixelData.length; i++)
{
sender.writeInt(pixelData[i]); //write pixel data
}
}
}
我的方法2的实现,在服务器上显示接收到的图像;
try (DataInputStream rcv = new DataInputStream(new BufferedInputStream(socket.getInputStream()))) //never use DataStreams without buffering, too slow
{
while (true)
{
int frameWidth = rcv.readInt(); //read image with
int frameHeight = rcv.readInt(); //read image height
int[] pixelData = new int[frameWidth * frameHeight];
for (int i = 0; i < pixelData.length; i++)
{
pixelData[i] = rcv.readInt(); //read pixel data
}
BufferedImage frame = new BufferedImage(frameWidth, frameHeight, BufferedImage.TYPE_INT_RGB); //create immage
frame.setRGB(0, 0, frameWidth, frameHeight, pixelData, 0, frameWidth); //set pixel data
//do whatever you want with frame
}
}
:
Server.java
public class Server
{
public static void main (String[] args) throws IOException, ClassNotFoundException
{
ServerSocket server = new ServerSocket(54339);
Socket socket = server.accept();
JFrame jframe = new JFrame();
jframe.setSize(800, 600);
jframe.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jframe.setLayout(new BorderLayout());
ImageDisplayPanel imageDisplayPanel = new ImageDisplayPanel();
jframe.add(imageDisplayPanel, BorderLayout.CENTER);
jframe.setVisible(true);
try (DataInputStream rcv = new DataInputStream(new BufferedInputStream(socket.getInputStream())))
{
while (true)
{
int frameWidth = rcv.readInt();
int frameHeight = rcv.readInt();
int[] pixelData = new int[frameWidth * frameHeight];
for (int i = 0; i < pixelData.length; i++)
{
pixelData[i] = rcv.readInt();
}
BufferedImage frame = new BufferedImage(frameWidth, frameHeight, BufferedImage.TYPE_INT_RGB);
frame.setRGB(0, 0, frameWidth, frameHeight, pixelData, 0, frameWidth);
imageDisplayPanel.setBackground(frame);
}
}
}
private static class ImageDisplayPanel extends JPanel
{
private static final Object BACKGROUND_LOCK = new Object();
private BufferedImage background = null;
public ImageDisplayPanel () throws HeadlessException
{
this.setDoubleBuffered(true); //to avoid flicker
}
public void setBackground (Image newBackground)
{
synchronized (BACKGROUND_LOCK)
{
if (background == null)
{
background = new BufferedImage(newBackground.getWidth(null), newBackground.getHeight(null), BufferedImage.TYPE_INT_RGB);
}
else if (background.getWidth() != newBackground.getWidth(null) || background.getHeight() != newBackground.getHeight(null))
{
background.flush();//flush old resources first
background = new BufferedImage(newBackground.getWidth(null), newBackground.getHeight(null), BufferedImage.TYPE_INT_RGB);
}
Graphics graphics = background.createGraphics();
graphics.drawImage(newBackground, 0, 0, null);
}
repaint();
}
@Override
public void paint (Graphics g)
{
super.paint(g);
synchronized (BACKGROUND_LOCK)
{
if (background != null)
{
g.drawImage(background, 0, 0, getWidth(), getHeight(), null);
}
}
}
}
}
:
Client.java