我遇到了与内存泄漏有关的问题。在我的应用程序中,我必须从视频文件中读取2MB数据,并且当Activity的onCreate方法调用时,相关的方法始终调用,然后在代码中分配2MB字节数组的相同语句,在经过事务后返回OutofMemory异常因为堆内存超过10到15次尝试。代码解释如下(这是我整个代码的一部分):
//Reading DRM video from sdcard
File file = new File("/sdcard/TvAnyTime/watch/"+IDValue+".mp4");
try {
is = new FileInputStream(file);
} catch (FileNotFoundException e2) {
e2.printStackTrace();
}
//reading 2^21 bytes
fileData = new byte[2097152];
int read = 0;
while(read != fileData.length) {
try {
read += is.read(fileData, read, fileData.length - read);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//The finalHashPattern is then xored across the video file 2^10 times
for(int i=0;i<2097152;i+=2048)
{
byte[] res = new byte[2048];
bytesafterXor = new byte[2048];
for(int j=0;j<2048;j++)
{
res[j] = fileData[i+j];
bytesafterXor[j] = (byte)(res[j]^finalhash[j]);
finaldatafile[i+j] = bytesafterXor[j];
}
finalHashafterXor.add(bytesafterXor);
}
语句fileData = new byte[2097152];
负责OutOfMemory异常,因为每次调用onCreate时都会分配它。我们可以通过每次分配大内存来阻止它吗?我们可以用大块的数据来读它吗?请建议我正确的解决方案。
提前致谢。
答案 0 :(得分:2)
您是否考虑过处理读取字节的循环内的输入,而不是读取所有字节
fileData = new byte[2048];
int read = 0;
while(read != fileData.length) {
try {
read += is.read(fileData, read, fileData.length);
for(int i = 0; i < 2048; i++) {
// Processing here
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
答案 1 :(得分:1)
你可以将 fileData 作为静态指针,然后 onCreate 只分配内存一次,当 fileData == NULL ;
答案 2 :(得分:0)
您可以将此关键文件处理从Java代码排除到本机代码。 http://marakana.com/forums/android/examples/49.html
答案 3 :(得分:0)
好的,因为我在等待同行评审时对“神秘”的Kingamajick的答案的编辑消失了,所以这里是如何将文件(或一般的流)整理成一个块:
fileData = new byte[2048];
try {
int c = 0;
while( (c = is.read(fileData)) >= 0 ) {
// Process all bytes from fileData[0] through fileData[c-1], e.g.:
for(int i = 0; i < c; i++) {
// do something with fileData[i]
// ...
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
请注意,对于文件,缓冲区(上面的fileData
)很可能总是被读取操作完全填充,直到文件中没有足够的字节来读取。例如,当从网络流中读取时,通常不是这种情况,因为数据并不总是立即可用,并且当它变得可用时,它可能与最后一个网络数据包中到达的数据一样多。但是,上述方法适用于所有流。
编辑:
从你的评论中我认为你不想处理整个文件而只需要处理前2mb。在这种情况下,您可以稍微修改上述方法,例如:
fileData = new byte[2048];
int leftToRead = 2048*1024; // Total amount of bytes you want to read.
try {
int c = 0;
// How many bytes may we read at once?
int maxRead = Math.min( fileData.length, leftToRead );
while( (leftToRead > 0) && (c = is.read(fileData, 0, maxRead)) >= 0 ) {
// Process all bytes from fileData[0] through fileData[c-1], e.g.:
for(int i = 0; i < c; i++) {
// do something with fileData[i]
// ...
}
// We read c bytes, so we may have some bytes left:
leftToRead -= c;
// How many bytes may we read at once?
maxRead = Math.min( fileData.length, leftToRead );
}
// Optionally:
if ( leftToRead > 0 ) {
System.out.println("Premature end of file.");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
当您在代码摘录中逐字节处理文件时,您基本上可以自由选择fileData
缓冲区的大小。较小的缓冲区不会提供任何实际好处,因为它可能会对底层文件系统造成更多的读取操作。从1kb到64kb的范围通常是一个很好的尺寸。