如何解决java.lang.OutOfMemoryError:在增加堆大小的情况下Java堆空间将意味着延迟OutOfMemoryError

时间:2014-03-20 22:40:28

标签: java out-of-memory

我正在尝试构建一个客户端将其屏幕发送到服务器的应用程序,如果上次发送屏幕和最新捕获的屏幕之间存在差异,则客户端仅发送其屏幕(以便程序在网络)。服务器使用JFrame和JLabel来显示图像。但事情是在一两分钟之后服务器提供java.lang.OutOfMemoryError:Java堆空间。

请考虑我的代码

public  void go() throws Exception
{
  s=new Socket("127.0.0.1",5000);
  remoteIP = s.getInetAddress(); 
  remoteIPOnly = remoteIP.toString().split("\\/");
  frame=new JFrame(remoteIPOnly[1]);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  InputStream iss=s.getInputStream();
  ObjectInputStream is=new ObjectInputStream(iss);
  JLabel a=new JLabel();
  while(!s.isClosed())
    {
      if((ImageIcon)is.readObject()!=null)
         {
           System.out.println("I got here");
           imageIcon=(ImageIcon) is.readObject();
           image=imageIcon.getImage();
           rendered = null;  
           if (image instanceof RenderedImage)  
              {  
                 rendered = (RenderedImage)image;  
              }   
           else  
              {  
               buffered = new BufferedImage(  
               imageIcon.getIconWidth(),  
               imageIcon.getIconHeight(),  
               BufferedImage.TYPE_INT_RGB  
               );  
               g = buffered.createGraphics();  
               g.drawImage(image, 0, 0, null);  
               g.dispose();  
               rendered = buffered;  
              }
           frame.setSize(rendered.getWidth(),rendered.getHeight());
           a.setIcon(imageIcon);
           frame.add(a);
           frame.setVisible(true);

         }
       }
}

这是我的另一段代码,它也显示了同样的问题,请帮助我优化它。

 while(true)
 {
   s=serversocket.accept();
   os=s.getOutputStream();
   oss=new ObjectOutputStream(os);
image1=r.createScreenCapture(newRectangle(Toolkit.getDefaultToolkit().getScreenSize()));
  imageicon=new ImageIcon(image1);
  oss.writeObject(imageicon);
  while(!s.isClosed()){
  image2=r.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit
  ().getScreenSize()));
  b=checkIfImagesAreEqual(image1,image2);
  System.out.println(b);
  if(b==false){
  image1=image2;
  imageicon1=new ImageIcon(image2);
  oss.writeObject(imageicon1);
  oss.flush();
 }

任何人都可以告诉我,为了我的目的我的逻辑是否正确以及为什么我得到java.lang.OutOfMemoryError:Java堆空间并扩展堆大小帮助我,因为我计划多个客户端能够连接到服务器吗?

很抱歉,如果我的问题很愚蠢,我们将不胜感激任何帮助。谢谢。

2 个答案:

答案 0 :(得分:4)

您继续将标签添加到框架中。你不应该只添加一次吗?

还有一个问题:if((ImageIcon)is.readObject()!=null)会读出一张图片并丢失它。您应该保留它而不是在if块内读取它。例如:

if((imageIcon = (ImageIcon)is.readObject()) != null)

答案 1 :(得分:1)

手动处理大型对象后,需要手动发出垃圾回收信号。此外,一般优化将有所帮助。

我建议(在你的客户端):

  1. 创建框架
  2. 创建足够大小的BufferedImage以绘制传入图像。
  3. 将所述BufferedImage添加到ImageIcon
  4. 将所述ImageIcon添加到您的JLabel
  5. 将所述JLabel添加到所述框架
  6. 调整框架大小
  7. 显示框架
  8. 然后在你的循环中

    1. 读入图像(仅图像,而不是ImageIcon)
    2. 获取上述BufferedImage的图形上下文
    3. 将收到的图像绘制到上述背景中。
    4. 删除指向图像的指针
    5. 致电System.gc();
    6. 看看情况如何。哦,如果你的入站图片大小不一,你可能想要在再次绘制它之前擦除BufferedImage,否则你会得到时髦的边框: - )

      至于你的服务器,它看起来还不错,我只是放弃了ImageIcons而只是传递普通的旧图像。像这样:

      开始循环

      1. 接受套接字(正如你所做)
      2. 获取对象输出流(正如您所做)
      3. 获取image1(正如你所做)
      4. 写image1
      5. 开始内循环

        1. 获取image2(正如你所做)
        2. 比较图像(正如你所做)
        3. 如果(!b)(b == false有效;它只是一种奇怪的写作方式)
        4. image1 = image2
        5. System.gc()(因为先前的分配删除了指向旧image1的指针)
        6. 写image1
        7. 刷新流(正如你所做)
        8. 如果完全清晰的图像不是强制性的,您也可以考虑压缩图像 在发送之前,只是将其作为字节数组处理;你输入的信息要少得多。

          public static byte[] bufferedImageToJPEGBytes(BufferedImage bi){
              try{
                  ByteArrayOutputStream baos = new ByteArrayOutputStream();
                  ImageIO.write(bi, "jpg", baos);
                  return baos.toByteArray();
              } catch (IOException e){
                  return null;
              }
          }
          
          public static BufferedImage jpegBytesToBufferedImage(byte[] bytes){
              try{
                  ByteArrayInputStream bais = new ByteArrayInputStream(rightImageBytes);
                  return ImageIO.read(bais);
              } catch (IOException e){
                  return null;
              }
          }
          

          然后只需使用

          oos.writeObject(bufferedImageToJPEGBytes(image1)); //server side
          

          image = jpegBytesToBufferedImage((byte[]) ois.readObject()); //client side