我想实现网络传输大量图片,于是用ObjectOutputStream和ObjectInputStream来传送(压缩后)转化为byte数组的图片,程序一开始运行正常,但等过了五分钟左右,接收图片端会出现java.lang.OutOfMemoryError。于是我用eclipse的插件MemoryAnalyzer检查了出问题时的堆栈状态,发现有一个ObjectInputStream的实例对象(注:我的程序中只建了一个ObjectInputStream的实例,用来读取byte数组,这个实例在我的程序运行过程中没有close过,接收所有的byte数组都始终在用这一个实例)竟占了整个Java虚拟机内存的90.15%!进一步往下看我发现(如下图)似乎发送过的byte数组全被保存到了一个与ObjectInputStream有关的Object数组中了(有606个之多)。这个问题感觉上不是我自己写的代码导致的问题,好象是ObjectInputStream本身的问题,而我也看了一下ObjectInputStream的方法,似乎没有与这个有关的。实在是没办法了,请各位高手帮忙解决啊!
解决方案 »
- 我们的服务器在linux下!但是我们都是在windows下调试然后直接将class.ftp到linux
- 如何用JAVA的GUI 做个简单的压缩程序 ?
- 类clone()问题
- Log4j无法生成日志文件
- 有些问题可以说的详细点么
- 马上给分:sun的j2ee服务器版sdk能在win2000 professional 下运行吗?
- 从网上下载的很多大软件都是 *.rpm *.iso格式的谁知道怎么用???up有分!
- 如何打开jpanel???????、、、在线等待!!!!
- 新手提问,为什么我import java.util.Calendar;后,Calendar c=new Calendar.getInstance();却抱错呢??谢谢
- 又一个java mail的问题!。。谢谢赐教!
- 请问高手关于java3d的问题
- java多线程的情况下如何进行调试?
以前也遇到过, 这是你程序写的有问题,当你在发送端每发送完一个对象后,就要调用相应的flush()方法,把对象给发到另一端去.不然对象多了就会出这种问题
希望有用.
是不是一下子传的图片过多 对方一个一个字节得没来得及接受 你这儿一直在上传 就内存溢出了。。
另外,建议使用有buffer的流楼主可以把byte数组设的小点,然后循环读取
这样每次循环会把byte数组清空另外,说得再多,方便的话,上代码吧
ObjectInputStream和ObjectOutputStream搭配使用,用来实现java对象的序列化存储和读入。
而你要传输大量的图片,我觉得选择带缓冲的普通字节流更合适。另外,在我的理解里,ObjectInputStream只负责读数据,而不负责保存数据。
例如,javadoc中有如下的例子: FileInputStream fis = new FileInputStream("t.tmp");
ObjectInputStream ois = new ObjectInputStream(fis); int i = ois.readInt();
String today = (String) ois.readObject();
Date date = (Date) ois.readObject();读出来的数据都是保存在变量中的。就比如,用抽水机把池塘里的水抽到田里。
ObjectInputStream只是一个抽水机。所以说,问题不在ObjectInputStream里。
ObjectInputStream和ObjectOutputStream搭配使用,用来实现java对象的序列化存储和读入。
我这句话的重心在后面。
import java.io.*;public class St { public static void main(String[] args) throws Exception
{
ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream("st.serial"));
for(int i = 1; i < 0x40000000; i++)
{
oout.writeObject(new MySerialCls(i, String.valueOf(i)));
oout.flush();
//System.gc();
System.out.println(i);
}
oout.close();
ObjectInputStream oin = new ObjectInputStream(new FileInputStream("st.serial"));
while(true)
{
try
{
Object o = oin.readObject();
if(o == null)
break;
System.out.println(o);
//System.gc();
}
catch(EOFException e)
{
break;
}
}
oin.close();
}}//MySerialCls.java
import java.io.Serializable;public class MySerialCls implements Serializable
{
private int a;
private String b;
public MySerialCls(int a, String b)
{
this.a = a;
this.b = b;
}
public int getA()
{
return a;
}
public void setA(int a)
{
this.a = a;
}
public String getB()
{
return b;
}
public void setB(String b)
{
this.b = b;
}
public String toString()
{
return "MySerialCls[a=" + a + ",b=" + b + "]";
}
}
Java不是有个视频聊天组件么.. 而且不用一张张读JPG 而是定时去读视频播放流吧 LZ思维够灵活 运用了最原始的动画手段 佩服 佩服..
谢谢指导,您说的那个组件应该是JMF中的吧,是个不错的选择,我先研究研究,有了问题再请教大家。不过,我最开始提出的问题还是没有解决,虽然我打算改用JFM,但我还是很想知道为什么会出现内存溢出,我读取数据是在一个方法中进行的,得到的数据是存在该方法中定义的局部变量中,所以每次方法结束都会释放,但不知为啥,根据内存状态监测,莫名其妙的出现了一个Objct数组,里面似乎存着所有我读过的数据,把内存占完了,这是不是就是传说中的"内存泄漏"?
希望有高手能仔细看看我发的图,告知我图中那个Object数组的来历(图中显示的应该是包含关系,"java.io.ObjectInputStream @ 0x2492df20"里包含"java.io.ObjectInputStream$HandleTable@0x2492e0e8"而"java.io.ObjectInputStream$HandleTable @ 0x2492e0e8"里包含"java.lang.Object[703] @ 0x26802958",这一切似乎真的与那个ObjectInputStream的对象有关。
private BufferedImage image;
private ObjectOutputStream out;
private ObjectInputStream in; /**
*
* @param Socket 用于进行操控的服务端Socket
* @param input 即new ObjectIntputStream(socket.getInputStream())
* @param output 即new ObjectOutputStream(socet.getOutputStream())
*/
public ScreenViewer(Socket Socket, ObjectInputStream input, ObjectOutputStream output) {
super();
this.socket = Socket;
image = null;
in = input;
out = output;
}
/**
* 获取服务端传来的图像的线程
*/
@Override
public void run() { while (true) {
getImage();
} } /**
* 从服务端获取的输入流中读取图像对象,并用JPEG进行解码
* 显示在本类的对象(JLabel)中(用paint()方法drawImage)
*/
private void getImage() {
try {
Object bufIn = in.readObject();
byte[] buffer = (byte[]) bufIn;
ByteArrayInputStream byteIn = new ByteArrayInputStream(buffer); JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(byteIn);
BufferedImage image = decoder.decodeAsBufferedImage();
this.image = image;
this.setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
this.updateUI(); bufIn = null;
buffer = null;
byteIn.close();
byteIn = null;
decoder = null;
image = null;
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 覆盖父类paint()方法,用于绘制从服务端传来的图像
*/
public void paint(Graphics g) {
super.paint(g);
if (image != null) {
g.drawImage(image, 0, 0, this);
} }
public static void main(String[] args){
Socket socket=new Socket("127.0.0.1",8888);
ScreenViewer client=new ScreenViewer(socket,
socket.getInputStream(),socket.getOutputStream());
new Thread(client).start();
}}
间隔一工作量后重置就可以了
for(int i = 1; i < 0x40000000; i++)
{
oout.writeObject(new MySerialCls(i, String.valueOf(i)));
oout.flush();
if(i%100000==0)
oout.reset();
System.out.println(i);
}
间隔一工作量后重置就可以了 ”
如果我们 A a = new A();a.setName("1");outputStream.writeObject(a);a.setName("2");outputStream.writeObject(a);两次连续调用你会发现接收端收到的对象的 getName() 返回相同的值,就跟你没调用第二次的 writeObject 一样的效果,具体是发送端没有发第二次还是接收方发现收到的对象标志在已接收对象缓存中已经存在而丢弃不尝试构造对象的内存镜像这个就需要我们用网络抓包程序抓包再证实网络上是否有数据流量存在并且流量的大小是否对应着一个对象的估计的字节数,这个我没试过。有兴趣的试试。