2014-07-27 21 views
0

我有一个读取资产文件并将其内容存储在数组中的函数。这是一个代码。读取多个资产时OutOfMemoryError

private List<String> infinitivesDB; 
private List<String> formsDB; 

private void getDB(String lang, String type) 
    { 
     while(true) 
     { 
     try { 
      String infinitivesDB = getStringFromAssetFile(this, "inf.txt"); 
      this.infinitivesDB = new LinkedList(Arrays.asList(infinitivesDB.split("\n"))); 
      break; //would be needed if it was reachable 
     } catch (IOException e) {   
      e.printStackTrace(); 
      } 
    } 
     while(true) 
     { 
     try { 
      String formsDB = getStringFromAssetFile(this, "forms.txt");//EXCEPTION HERE?   
      this.formsDB = new LinkedList(Arrays.asList(formsDB.split("\n"))); 
      break; //would be needed if it was reachable 
     } catch (IOException e) {   
      e.printStackTrace(); 
      } 
    } 
    } 

文件“inf.txt”是58kb。文件“forms.txt”是3.5 Mb。

每当我尝试运行此代码,它提出了一个OutOfMemoryError。这里的日志

07-27 02:40:13.399: E/AndroidRuntime(2017): FATAL EXCEPTION: main 
07-27 02:40:13.399: E/AndroidRuntime(2017): Process: com.highstaker.formdictionary, PID: 2017 
07-27 02:40:13.399: E/AndroidRuntime(2017): java.lang.OutOfMemoryError 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at java.util.Scanner.expandBuffer(Scanner.java:2067) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at java.util.Scanner.readMore(Scanner.java:2031) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at java.util.Scanner.findDelimiterAfter(Scanner.java:2009) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at java.util.Scanner.setTokenRegion(Scanner.java:1923) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at java.util.Scanner.hasNext(Scanner.java:541) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at java.util.Scanner.hasNext(Scanner.java:519) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at com.highstaker.formdictionary.MainActivity.convertStreamToString(MainActivity.java:411) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at com.highstaker.formdictionary.MainActivity.getStringFromAssetFile(MainActivity.java:404) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at com.highstaker.formdictionary.MainActivity.getDB(MainActivity.java:389) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at com.highstaker.formdictionary.MainActivity.onCreate(MainActivity.java:50) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at android.app.Activity.performCreate(Activity.java:5243) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2140) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2226) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at android.app.ActivityThread.access$700(ActivityThread.java:135) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1397) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at android.os.Handler.dispatchMessage(Handler.java:102) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at android.os.Looper.loop(Looper.java:137) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at android.app.ActivityThread.main(ActivityThread.java:4998) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at java.lang.reflect.Method.invokeNative(Native Method) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at java.lang.reflect.Method.invoke(Method.java:515) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593) 
07-27 02:40:13.399: E/AndroidRuntime(2017):  at dalvik.system.NativeStart.main(Native Method) 
07-27 02:40:15.179: I/Process(2017): Sending signal. PID: 2017 SIG: 9 

但是,如果我尝试读取只有一个文件(通过注释掉的while循环和它的内容之一),无论我选择哪个文件 - 它工作正常。如果我尝试在两个循环中读取“inf.txt”(较小)并存储在这些不同的数组中,它也可以正常工作。

而且,如果我只需将“田地”,因此读小一前较大的文件,它也可以!

我想知道为什么会发生这种情况。另外,如果两个资产文件都很大,我又该如何阅读?我试图在两个循环中读取“forms.txt”(更大),并提出了相同的错误(我预料到,真的)。

+0

我怀疑错误来自这段代码。请参阅http://sscce.org/ – Unihedron

+0

问题是更多的方法'getStringFromAssetFile'你可以发布它的代码。 –

回答

0

错误正在导致因为您正试图从3.5 MB文件中加载大量的字符串数据。用于此目的的快速解决方案是

可以使用Android:largeHeap =“true”将要求更大的堆大小,但这不会对任何预先蜂窝设备上运行。在2.3之前的设备上,您可以使用VMRuntime类,但这不适用于Gingerbread及更高版本。

只有这样,才能有大的限制尽可能是通过NDK做内存密集型任务,如NDK不会强加内存限制类的SDK。

或者,你只能加载当前鉴于模型的一部分,因为你需要它,而从内存中删除未使用的部分加载休息。但是,这可能无法实现,具体取决于您的应用程序。

在API级别11+上运行的应用程序可以在清单中的元素上使用android:largeHeap =“true”来请求大于正常的堆大小,并且ActivityManager上的getLargeMemoryClass()会告诉您该堆有多大是。但是:

在API级别这只适用11+(即蜂巢外)

没有保证的大型堆将有多大

用户会感觉到你的大堆的要求,因为它会迫使他们的其他应用程序从RAM中终止其他应用程序的进程释放系统RAM供大堆使用

由于#3,并且我期望android:largeHeap将被滥用,支持因为这可能在将来被放弃,或者用户可能会在安装时被警告(例如,您将需要员工要求获得特别许可)

目前,此功能是记录轻轻

0

我可以在这里看到一些不好的设计决策。最重要的是:如果你需要一个文件作为字符串列表,为什么不直接阅读它?

使用扫描仪读取数据流,这本身并不是必需的。其他的io课程让你阅读没有这种复杂的线条。

looong字符串是拆分成一个大数组,最终会产生列表。因此,您至少有三次重复的内存文件。

LinedList高效增长,但您不需要这里。 ArrayList更节省空间。

getStringFromAssetFile必须重新设计。