我有一个应用程序可以在线下载csv文件,然后将其保存在本地,这样即使应用程序处于脱机状态,该应用也能正常运行。我的问题是当用户关闭应用程序然后立即再次打开它时,应用程序挂起,同时解析保存的csv文件并抛出OutOfMemoryError。但是,我注意到,当我在几分钟后再次打开应用程序时,它工作正常。 下载,解析和保存在不同的线程上完成。 有什么可以解决这个问题?
答案 0 :(得分:1)
一种可能性:内存错误可能更多地与过度工作的GC相比而不是实际的内存不足。如果你分配大块内存,然后释放它们,然后分配更大的部分,你就会得到一个点,你有很多大量的空闲内存占用空间但是因为它们不够大而无法使用。 GC疯狂地试图移动东西并将这些部分合并到一个连续的块中以进行下一次分配,但不是看起来很糟糕,因为它耗时太长,它只会抛出OutOfMemory异常,即使理论上90%的内存可用(并且如果你能给它一分钟,它将可用。)
在你的情况下,我怀疑是ArrayList。它保留了一系列参考。在添加条目时,它会添加到数组中。当它从最后运行时,它会分配一个新的,更大的,并释放旧的。如果你忙着把这些丢弃物堆积起来。哈希表有类似的问题。 LinkedList和TreeMap没有,因为它们可以处理少量内存。
我对Android并不太了解,但是我猜测当你短暂关闭它时应用程序并没有真正关闭,所以当你重新启动它时,它就像以前那样是一个与自由内存碎片相同的执行。如果你等待一段时间,它可能是一个新的执行。即使不是这样,GC也有时间清理,你也没事。
您想要的解决方案可能是每次“启动”系统时强制进行垃圾收集(System.gc())。它为GC提供了在为您分配空间之前将所有内容整理好的机会,并且不会花费很长时间。从某种意义上说,你授予GC许可,可以将你的程序锁定半秒钟,这是它自己不会做的。 (如果确实如此,它会选择一个尴尬的时间来做 - 当用户输入文字时,比方说。)
使用链接集合避免使用大型数组是另一种解决方案,但阵列速度很快,当您可以节省半秒的用户时间时,没有理由进行切换。
希望这会有所帮助。如果这次不是问题,可能会是下一次。
添加:不幸的是,System.gc()只是一个“建议”。它可能没有完成我们希望它会做的工作。或者你可能在通话后遇到麻烦。我之前应该提到的另一个重要修复是设置ArrayList上的初始大小非常大,如果这是您正在使用的。使它成为它所需尺寸的两到三倍,可能会在运行中节省十倍的内存量 - 并节省时间。这适用于任何基于数组的结构(哈希表和普通数组)。除此之外,像LinkedList这样的基于指针的结构如果能解决它们的缺点就不会有这个问题。