在我的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();
}
答案 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
。