Android App 运行 进入 java.lang.OutOfMemoryError 而 EDF 文件解析
Android App running into java.lang.OutOfMemoryError while EDF file parsing
我搜索了类似的主题,但找不到与 EDF 文件和内存不足错误相关的任何内容。
所以,这是我的问题:
我正在 Android studio 中开发一个 Android 应用程序,它可以浏览文件、选择“.edf”文件并对其进行解析。但对于某些文件,它会抛出以下错误(使用堆栈跟踪):
I/xample.styleap: Starting a blocking GC Alloc
Starting a blocking GC Alloc
I/xample.styleap: Alloc concurrent copying GC freed 15804(1107KB) AllocSpace objects, 5(108KB) LOS objects, 86% free, 1955KB/13MB, paused 148us total 44.577ms
Starting a blocking GC Alloc
I/xample.styleap: Alloc young concurrent copying GC freed 0(15KB) AllocSpace objects, 0(0B) LOS objects, 86% free, 1955KB/13MB, paused 120us total 16.603ms
Starting a blocking GC Alloc
I/xample.styleap: Alloc concurrent copying GC freed 2019(110KB) AllocSpace objects, 0(0B) LOS objects, 86% free, 1844KB/13MB, paused 83us total 25.049ms
Forcing collection of SoftReferences for 488MB allocation
Starting a blocking GC Alloc
I/xample.styleap: Alloc concurrent copying GC freed 2053(69KB) AllocSpace objects, 0(0B) LOS objects, 87% free, 1790KB/13MB, paused 75us total 22.140ms
W/xample.styleap: Throwing OutOfMemoryError "Failed to allocate a 512000012 byte allocation with 12582912 free bytes and 190MB until OOM, target footprint 14416192, growth limit 201326592" (VmSize 1212600 kB)
I/xample.styleap: Starting a blocking GC Alloc
Starting a blocking GC Alloc
I/xample.styleap: Alloc young concurrent copying GC freed 4(31KB) AllocSpace objects, 0(0B) LOS objects, 87% free, 1774KB/13MB, paused 79us total 15.057ms
I/xample.styleap: Starting a blocking GC Alloc
I/xample.styleap: Alloc concurrent copying GC freed 3(16KB) AllocSpace objects, 0(0B) LOS objects, 87% free, 1774KB/13MB, paused 83us total 23.495ms
Forcing collection of SoftReferences for 488MB allocation
Starting a blocking GC Alloc
I/xample.styleap: Alloc concurrent copying GC freed 50(17KB) AllocSpace objects, 0(0B) LOS objects, 87% free, 1788KB/13MB, paused 73us total 22.532ms
W/xample.styleap: Throwing OutOfMemoryError "Failed to allocate a 512000016 byte allocation with 12582912 free bytes and 190MB until OOM, target footprint 14414784, growth limit 201326592" (VmSize 1212600 kB)
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.styleapp, PID: 30041
java.lang.OutOfMemoryError: Failed to allocate a 512000016 byte allocation with 12582912 free bytes and 190MB until OOM, target footprint 14414784, growth limit 201326592
at br.unb.biologiaanimal.edf.EDFReader.readRecords(EDFReader.java:106)
at br.unb.biologiaanimal.edf.EDFReader.<init>(EDFReader.java:25)
at br.unb.biologiaanimal.edf.EDF.<init>(EDF.java:24)
at com.example.styleapp.MainActivity.runEDFfile(MainActivity.java:100)
at com.example.styleapp.MainActivity.access[=13=]0(MainActivity.java:24)
at com.example.styleapp.MainActivity.onMenuItemClick(MainActivity.java:82)
at androidx.appcompat.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:154)
at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:991)
at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:981)
at androidx.appcompat.widget.ActionMenuView.invokeItem(ActionMenuView.java:625)
at androidx.appcompat.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:151)
at android.view.View.performClick(View.java:7140)
at android.view.View.performClickInternal(View.java:7117)
at android.view.View.access00(View.java:801)
at android.view.View$PerformClick.run(View.java:27355)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7410)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
W/System: A resource failed to call close.
我正在为 java 使用 EDF 解析器库:https://github.com/lab-neuro-comp/EDF
我的源代码(MainActivity.java):
import br.unb.biologiaanimal.edf.EDF;
EDF edf = new EDF(filepath);
使用特定文件路径调用 EDF 构造函数时失败。
在许多地方,据说由于 JVM/Android 或堆大小中的 VM 不足而导致失败。但我想我也已经处理好了:
里面studio.vmoptions
-Xmx2048m
我想这指定了 Android Studio 的 JVM VM 大小。
我还在打印 Java 虚拟机将尝试使用的最大内存量:
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
这会打印
201326592
这意味着大约有 201MB 可用。
那么当它成功加载一个4.2MB的EDF文件时,加载一个1.9MB的EDF文件失败(内存不足)的原因是什么?
由于 EDF 解析库的逻辑错误,它失败了。 EDF class 方法查找名为 "duration" 的 header(原因尚不清楚)并将其用于后续算术运算,其中使用 header 值分配数组内存等. 有时持续时间值是浮动的,这会导致错误的算术运算,结果值也会变得非常大。在那里它无法分配内存。
这是代码片段:
private void readRecords(FileInputStream stream)
throws IOException
{
records = new HashMap();
int[] numberSamples = getNumberSamples();
int[] sampling = new int[numberSignals];
int duration = paramToInt("duration");
int dataRecords = paramToInt("datarecords");
byte[][] recordList = new byte[numberSignals][5];
String[] labels = getLabels();
byte[] buffer = null;
// Initalizing variables
for (int i = 0; i < numberSignals; ++i)
{
sampling[i] = duration * numberSamples[i];
recordList[i] = null;
}
// Reading records
for (int d = 0; d < dataRecords; ++d)
{
for (int i = 0; i < numberSignals; ++i)
{
duration = 2 * sampling[i];
buffer = new byte[duration];
stream.read(buffer);
// TODO Make this insertion faster. Maybe a queue?
recordList[i] = (recordList[i] == null)?
buffer :
EDFUtil.insert(recordList[i], buffer);
}
}
// Packing records
for (int i = 0; i < numberSignals; ++i)
{
String label = labels[i].trim();
records.put(label, recordList[i]);
}
}
我搜索了类似的主题,但找不到与 EDF 文件和内存不足错误相关的任何内容。
所以,这是我的问题: 我正在 Android studio 中开发一个 Android 应用程序,它可以浏览文件、选择“.edf”文件并对其进行解析。但对于某些文件,它会抛出以下错误(使用堆栈跟踪):
I/xample.styleap: Starting a blocking GC Alloc
Starting a blocking GC Alloc
I/xample.styleap: Alloc concurrent copying GC freed 15804(1107KB) AllocSpace objects, 5(108KB) LOS objects, 86% free, 1955KB/13MB, paused 148us total 44.577ms
Starting a blocking GC Alloc
I/xample.styleap: Alloc young concurrent copying GC freed 0(15KB) AllocSpace objects, 0(0B) LOS objects, 86% free, 1955KB/13MB, paused 120us total 16.603ms
Starting a blocking GC Alloc
I/xample.styleap: Alloc concurrent copying GC freed 2019(110KB) AllocSpace objects, 0(0B) LOS objects, 86% free, 1844KB/13MB, paused 83us total 25.049ms
Forcing collection of SoftReferences for 488MB allocation
Starting a blocking GC Alloc
I/xample.styleap: Alloc concurrent copying GC freed 2053(69KB) AllocSpace objects, 0(0B) LOS objects, 87% free, 1790KB/13MB, paused 75us total 22.140ms
W/xample.styleap: Throwing OutOfMemoryError "Failed to allocate a 512000012 byte allocation with 12582912 free bytes and 190MB until OOM, target footprint 14416192, growth limit 201326592" (VmSize 1212600 kB)
I/xample.styleap: Starting a blocking GC Alloc
Starting a blocking GC Alloc
I/xample.styleap: Alloc young concurrent copying GC freed 4(31KB) AllocSpace objects, 0(0B) LOS objects, 87% free, 1774KB/13MB, paused 79us total 15.057ms
I/xample.styleap: Starting a blocking GC Alloc
I/xample.styleap: Alloc concurrent copying GC freed 3(16KB) AllocSpace objects, 0(0B) LOS objects, 87% free, 1774KB/13MB, paused 83us total 23.495ms
Forcing collection of SoftReferences for 488MB allocation
Starting a blocking GC Alloc
I/xample.styleap: Alloc concurrent copying GC freed 50(17KB) AllocSpace objects, 0(0B) LOS objects, 87% free, 1788KB/13MB, paused 73us total 22.532ms
W/xample.styleap: Throwing OutOfMemoryError "Failed to allocate a 512000016 byte allocation with 12582912 free bytes and 190MB until OOM, target footprint 14414784, growth limit 201326592" (VmSize 1212600 kB)
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.styleapp, PID: 30041
java.lang.OutOfMemoryError: Failed to allocate a 512000016 byte allocation with 12582912 free bytes and 190MB until OOM, target footprint 14414784, growth limit 201326592
at br.unb.biologiaanimal.edf.EDFReader.readRecords(EDFReader.java:106)
at br.unb.biologiaanimal.edf.EDFReader.<init>(EDFReader.java:25)
at br.unb.biologiaanimal.edf.EDF.<init>(EDF.java:24)
at com.example.styleapp.MainActivity.runEDFfile(MainActivity.java:100)
at com.example.styleapp.MainActivity.access[=13=]0(MainActivity.java:24)
at com.example.styleapp.MainActivity.onMenuItemClick(MainActivity.java:82)
at androidx.appcompat.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:154)
at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:991)
at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:981)
at androidx.appcompat.widget.ActionMenuView.invokeItem(ActionMenuView.java:625)
at androidx.appcompat.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:151)
at android.view.View.performClick(View.java:7140)
at android.view.View.performClickInternal(View.java:7117)
at android.view.View.access00(View.java:801)
at android.view.View$PerformClick.run(View.java:27355)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7410)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
W/System: A resource failed to call close.
我正在为 java 使用 EDF 解析器库:https://github.com/lab-neuro-comp/EDF
我的源代码(MainActivity.java):
import br.unb.biologiaanimal.edf.EDF;
EDF edf = new EDF(filepath);
使用特定文件路径调用 EDF 构造函数时失败。 在许多地方,据说由于 JVM/Android 或堆大小中的 VM 不足而导致失败。但我想我也已经处理好了:
里面studio.vmoptions
-Xmx2048m
我想这指定了 Android Studio 的 JVM VM 大小。 我还在打印 Java 虚拟机将尝试使用的最大内存量:
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
这会打印
201326592
这意味着大约有 201MB 可用。
那么当它成功加载一个4.2MB的EDF文件时,加载一个1.9MB的EDF文件失败(内存不足)的原因是什么?
由于 EDF 解析库的逻辑错误,它失败了。 EDF class 方法查找名为 "duration" 的 header(原因尚不清楚)并将其用于后续算术运算,其中使用 header 值分配数组内存等. 有时持续时间值是浮动的,这会导致错误的算术运算,结果值也会变得非常大。在那里它无法分配内存。 这是代码片段:
private void readRecords(FileInputStream stream)
throws IOException
{
records = new HashMap();
int[] numberSamples = getNumberSamples();
int[] sampling = new int[numberSignals];
int duration = paramToInt("duration");
int dataRecords = paramToInt("datarecords");
byte[][] recordList = new byte[numberSignals][5];
String[] labels = getLabels();
byte[] buffer = null;
// Initalizing variables
for (int i = 0; i < numberSignals; ++i)
{
sampling[i] = duration * numberSamples[i];
recordList[i] = null;
}
// Reading records
for (int d = 0; d < dataRecords; ++d)
{
for (int i = 0; i < numberSignals; ++i)
{
duration = 2 * sampling[i];
buffer = new byte[duration];
stream.read(buffer);
// TODO Make this insertion faster. Maybe a queue?
recordList[i] = (recordList[i] == null)?
buffer :
EDFUtil.insert(recordList[i], buffer);
}
}
// Packing records
for (int i = 0; i < numberSignals; ++i)
{
String label = labels[i].trim();
records.put(label, recordList[i]);
}
}