Java Applet的内存消耗

时间:2018-10-29 11:39:55

标签: java

在我的applet中,我有GET调用,可以从远程位置下载文件。当我尝试下载大约13MB的大文件时,Applet的内存消耗增加了50MB以上。我正在使用以下代码来获取内存消耗:

public static long getMemoryUsage()
{
    long memory = 0;
    // Get the Java runtime
    Runtime runtime = Runtime.getRuntime();
    memory = runtime.totalMemory() - runtime.freeMemory();
    return memory;
}

我的get呼叫的代码是

public  void getFiles(String filePath, long fileSize)throws MyException
    {
        InputStream objInputStream = null;
        HttpURLConnection conn = null;
        BufferedReader br = null;
        try 
        {
            URL fileUrl=new URL(filePath);
            final String strAPICall=fileUrl.getPath();
            final String strHost="some.test.com";
            final int iPort=1000;
            URL url = null;
            url = new java.net.URL
                        ( "https",
                                strHost, iPort , "/" + strAPICall,
                                new myHandler() );  

            conn = (HttpURLConnection)new HttpsURLConn(url);
            conn.setRequestMethod("GET");

            conn.connect();

            if (conn.getResponseCode() != 200) {

                objInputStream=conn.getInputStream();

                br = new BufferedReader(new InputStreamReader(
                (objInputStream)));

                String output;
                while ((output = br.readLine()) != null) {
                    System.out.println(output);

                }
                throw new MyException("Bad response from server", 
                            MyError.BAD_RESPONSE_ERROR);

            }
            else
            {

                notifyProgressToObservers(0);
                System.out.println("conn.getResponseCode()"+conn.getResponseCode());
                System.out.println("conn.getResponseMessage()"+conn.getResponseMessage());
                objInputStream  = conn.getInputStream();
                int count=objInputStream.available();

                System.out.println("Stream size: "+count);
                System.out.println("fileSize size: "+fileSize);
                byte []downloadedData = getBytesFromInputStream
                        (objInputStream, count,fileSize);
                notifyChunkToObservers(downloadedData);
                notifyIndivisualFileEndToObservers(true, null);

            }

        }
        catch (MyException pm)
        {
            throw new MyException
            (pm, MyError.CONNECTION_TIMEOUT);
        }
        catch (IOException pm)
        {
            throw new MyException
            (pm, MyError.CONNECTION_TIMEOUT);
        }
        catch (Exception e) 
        {

            notifyIndivisualFileEndToObservers(false,new MyException(e.toString()));
        }
        finally
        {
            System.out.println("Closing all the streams after getting file");
            if(conn !=null)
            {
                try
                {
                    conn.disconnect();
                }
                catch(Exception e)
                {

                }
            }
            if(objInputStream != null)
            {
                try {
                    objInputStream.close();
                } catch (IOException e) {

                }
            }
            if (br != null) 
            {
                try {
                    br.close();
                } catch (IOException e) {

                }
            }
        }

    }

在上述方法中,我尝试将日志记录为每行之后的内存消耗,发现在conn.connect();之后,即使我要下载的文件只有13MB,小程序的内存消耗也至少增加了50MB

任何地方都有内存泄漏吗?

编辑:添加了getBytesFromInputStream()的实现

public byte[] getBytesFromInputStream(InputStream is, int len, long fileSize)
            throws IOException 
    {
        byte[] readBytes= new byte[8192];
        ByteArrayOutputStream getBytes= new ByteArrayOutputStream();

        int numRead = 0;

        while ((numRead = is.read(readBytes)) != -1) {
            getBytes.write(readBytes, 0, numRead);
        } 


        return getBytes.toByteArray();
    }

2 个答案:

答案 0 :(得分:1)

是因为此行:

 byte []downloadedData = getBytesFromInputStream(objInputStream, count,fileSize);

在这里,您正在将文件的完整字节读取到堆中。之后,您需要跟踪此数组会发生什么。也许您正在将其复制到某个地方,即使您不再使用对该对象的引用,GC也需要一些时间才能启动。

大文件绝对不应完整地读取到内存中,而应直接流式传输到数据的某些处理器。

答案 1 :(得分:1)

优化getBytesFromInputStream()的唯一方法是,如果您事先准确地 知道要读取多少字节。然后,分配所需大小的byte[],并从输入中直接读取到byte[]中。例如:

  byte[] buffer = new byte[len];
  int pos = 0;
  while (pos < len) {
     int nosRead = is.read(buffer, pos, len - pos);
     if (nosRead == -1) {
         throw new IOException("incomplete response");
     }
     pos += nosRead;
  }
  return buffer;

(有关更多信息,请阅读javadoc。)

不幸的是,您(显然)的尝试获取尺寸是错误的。

  int count = objInputStream.available();

这不会返回可以从流中读取的字节总数。它返回现在可以读取而不会阻塞的字节数。

如果服务器在响应中设置Content-Length标头,则可以使用它;收到响应后,请致电getContentLength()(或在其他用例中为getContentLengthLong())。但是请做好准备,以防给您-1