を仕事とObjectInputStream.readObject()
それらが受信/送信されたオブジェクトへのhard
references
のテーブルを保持していません。オブジェクトがObjectOutputStream
によって再送ときObjectInputStream
が以前に受信されたオブジェクトの参照に受信ハンドルを変換しながら、オブジェクトへのハンドルのみが送信されます。この機能は帯域幅とメモリ使用量を削減しますが、オブジェクトが定期的に再送信されるプログラムでのみ使用されます。 ObjectInputStream/ObjectOutputStream
これらのオブジェクトをハード参照するため、Garbage Collector
はそれらを収集できず、最終的にこれらのオブジェクトはメモリリークになりました。これを避けるために
、JavaはObjectOutputStream.writeUnshared()
とObjectInputStream.readUnshared()
方法を提供していますが、これらの方法も知られているメモリは、その問題についての詳細はJDK-6525563 : Memory leak in ObjectOutputStreamをチェックし、問題をリークしています。
ですから、2つのオプションがあります。 ObjectInput/OutputStream
を使用して
- 利用
read/writeUnshared()
代わりのread/writeObject()
とObjectOutputStream
によってリークしたメモリを解放するために、すべてたまにObjectOutputStream
のreset()
メソッドを呼び出して、
- は避けてください。このように
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
}
}
}
読書:
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
}
}
また、サーバー上で受信した画像を表示すると方法2の私の実装。
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
:
public class Client
{
public static void main (String[] args) throws IOException
{
Webcam wCam = null;
try (DataOutputStream sender = new DataOutputStream(new BufferedOutputStream(new Socket("127.0.0.1", 54339).getOutputStream())))
{
wCam = Webcam.getDefault();
wCam.setViewSize(WebcamResolution.VGA.getSize());
wCam.open();
while (true)
{
BufferedImage frame = wCam.getImage(); //get frame from webcam
int frameWidth = frame.getWidth();
int frameHeight = frame.getHeight();
sender.writeInt(frameWidth);
sender.writeInt(frameHeight);
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]);
}
}
} finally
{
//release resources used by library
if (wCam != null)
{
wCam.close();
}
Webcam.shutdown();
}
}
}