为什么程序会在特定智能手机上抛出 OutOfMemoryError?

Why does the program throw an OutOfMemoryError on a specific smartphone?

写了一个图形游戏程序。当我在模拟器和智能手机上编写测试时。一切都很好。然后他决定在另一部智能手机上试一试——程序在短时间后就失效了。抛出错误 - java.lang.OutOfMemoryError: Failed to allocate a 576012 byte allocation with 45728 free bytes and 44KB until OOM

在 AndroidStudio 中使用 Profiler 查看已用内存的大小。

我在智能手机上得到了这个结果,该智能手机上的程序通常 运行(可用 RAM - 750MB,版本 android 7.1.1):

Total - 115MB; Java - 74MB; Native - 5,8MB; Graphics - 7,6MB; Stack - 0,6MB; Code - 21,5 MB; Others - 5MB.

除 Java 外,所有值都是常数。此参数增长到大约 - 90MB。然后垃圾收集器删除所有不需要的参数(Java)再次降低到初始值。

在另一部智能手机上,也一切正常(可用 RAM - 500MB,android 版本 - 10):

Total - 161MB; Java - 13MB; Native - 100MB; Graphics - 9MB; Stack - 0,6MB; Code - 34 MB; Others - 7MB.

在这种情况下,只有 Native 参数从 60 变为 100MB

在 3rd 智能手机上,程序在游戏 1-2 分钟后崩溃。来自 Profiler 的数据:

Total - 166MB; Java - 81MB; Native - 11MB; Graphics - 35MB; Stack - 0,6MB; Code - 29 MB; Others - 5MB.

在这种情况下,只有 Java 参数从 70 变为 80MB(大约) 抛出错误 - java.lang.OutOfMemoryError:无法分配 576012 字节分配,其中 45728 个空闲字节和 44KB 直到 OOM (可用 RAM - 400MB,android 版本 - 7.0) 我注意到第三款智能手机加载图形参数的强度更大,可用内存更少,android 版本为 7.0。不知道这样会不会影响错误的出现。

告诉我可能是什么问题?

我postLOG文件的一个片段:

2021-02-26 12:51:22,824 [6294715]   INFO - ools.idea.run.tasks.DeployTask - Installing application: com.medinq.superlines 
2021-02-26 12:51:23,291 [6295182]   INFO - a.run.tasks.AbstractDeployTask - 284363961ms TRC_BEG [22751][22751] : installer 
2021-02-26 12:51:23,291 [6295182]   INFO - a.run.tasks.AbstractDeployTask - 284363965ms TRC_BEG [22751][22751] : Command Dump 
2021-02-26 12:51:23,291 [6295182]   INFO - a.run.tasks.AbstractDeployTask - 284363966ms TRC_BEG [22751][22751] : get process ids 
2021-02-26 12:51:23,292 [6295183]   INFO - a.run.tasks.AbstractDeployTask - 284364116ms LOG_ERR [22751][22751] : Could not get package user id: run-as: Could not set capabilities: Operation not permitted
 
2021-02-26 12:51:23,292 [6295183]   INFO - a.run.tasks.AbstractDeployTask - 284364117ms TRC_END [22751][22751] :  
2021-02-26 12:51:23,292 [6295183]   INFO - a.run.tasks.AbstractDeployTask - 284364117ms TRC_BEG [22751][22751] : CmdCommand::GetApksFromDump 
2021-02-26 12:51:23,292 [6295183]   INFO - a.run.tasks.AbstractDeployTask - 284364222ms TRC_END [22751][22751] :  
2021-02-26 12:51:23,292 [6295183]   INFO - a.run.tasks.AbstractDeployTask - 284364222ms TRC_BEG [22751][22751] : processing APK 
2021-02-26 12:51:23,292 [6295183]   INFO - a.run.tasks.AbstractDeployTask - 284364222ms TRC_END [22751][22751] :  
2021-02-26 12:51:23,292 [6295183]   INFO - a.run.tasks.AbstractDeployTask - 284364222ms TRC_END [22751][22751] :  
2021-02-26 12:51:23,292 [6295183]   INFO - a.run.tasks.AbstractDeployTask - 284364222ms TRC_END [22751][22751] :  
2021-02-26 12:51:25,216 [6297107]   INFO - a.run.tasks.AbstractDeployTask - Install successfully finished in 2 s 382 ms.. App restart successful without requiring a re-install. 
2021-02-26 12:51:26,834 [6298725]   INFO - run.AndroidLogcatOutputCapture - startCapture("samsung-sm_a510f-3300376233021439") 
2021-02-26 12:52:04,874 [6336765]   INFO - run.AndroidLogcatOutputCapture - stopCapture("samsung-sm_a510f-3300376233021439") 
2021-02-26 12:52:04,874 [6336765]   INFO - run.AndroidLogcatOutputCapture - stopAll() 
2021-02-26 12:52:19,115 [6351006]   INFO - j.ide.actions.RevealFileAction - Exit code 1 
2021-02-26 12:52:19,645 [6351536]   INFO - rationStore.ComponentStoreImpl - Saving appRegistry took 16 ms 
2021-02-26 12:54:04,487 [6456378]   INFO - ild.invoker.GradleBuildInvoker - About to execute Gradle tasks: [:app:assembleDebug] 
2021-02-26 12:54:04,503 [6456394]   INFO - s.plugins.gradle.GradleManager - Instructing gradle to use java from C:/Program Files/Android/Android Studio/jre 
2021-02-26 12:54:04,519 [6456410]   INFO - ild.invoker.GradleBuildInvoker - Build command line options: [-Pandroid.injected.invoked.from.ide=true, -Pandroid.injected.studio.version=10.4.1.1, -Pandroid.injected.attribution.file.location=C:\Users\Ura\AppData\Local\Temp14333244503-0, -Pandroid.injected.build.api=24, -Pandroid.injected.build.density=xxhdpi, -Pandroid.injected.build.abi=armeabi-v7a,armeabi] 
2021-02-26 12:54:04,519 [6456410]   INFO - xecution.GradleExecutionHelper - Passing command-line args to Gradle Tooling API: -Pandroid.injected.invoked.from.ide=true -Pandroid.injected.studio.version=10.4.1.1 -Pandroid.injected.attribution.file.location=C:\Users\Ura\AppData\Local\Temp14333244503-0 -Pandroid.injected.build.api=24 -Pandroid.injected.build.density=xxhdpi -Pandroid.injected.build.abi=armeabi-v7a,armeabi 
2021-02-26 12:54:05,266 [6457157]   INFO - ild.invoker.GradleBuildInvoker - Gradle build finished in 750 ms 
2021-02-26 12:54:05,267 [6457158]   INFO - a.gradle.run.MakeBeforeRunTask - Couldn't get post build models. 
2021-02-26 12:54:05,267 [6457158]   INFO - a.gradle.run.MakeBeforeRunTask - Gradle invocation complete, success = true 
2021-02-26 12:54:05,275 [6457166]   INFO - idea.run.AndroidProcessHandler - Adding device samsung-sm_a510f-3300376233021439 to monitor for launched app: com.medinq.superlines 
2021-02-26 12:54:05,278 [6457169]   INFO - notification.NotificationGroup - Notification group LaunchTaskRunner is already registered 
java.lang.Throwable
    at com.intellij.notification.NotificationGroup.<init>(NotificationGroup.kt:48)
    at com.intellij.notification.NotificationGroup.<init>(NotificationGroup.kt:28)
    at com.intellij.notification.NotificationGroup.<init>(NotificationGroup.kt:36)
    at com.intellij.notification.NotificationGroup.<init>(NotificationGroup.kt:36)
    at com.intellij.notification.NotificationGroup$Companion.toolWindowGroup(NotificationGroup.kt:93)
    at com.intellij.notification.NotificationGroup$Companion.toolWindowGroup$default(NotificationGroup.kt:92)
    at com.intellij.notification.NotificationGroup.toolWindowGroup(NotificationGroup.kt)
    at com.android.tools.idea.run.LaunchTaskRunner.run(LaunchTaskRunner.java:183)
    at com.intellij.openapi.progress.impl.CoreProgressManager$TaskRunnable.run(CoreProgressManager.java:932)
    at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcessWithProgressAsync(CoreProgressManager.java:434)
    at com.intellij.openapi.progress.impl.ProgressRunner.lambda$null(ProgressRunner.java:233)
    at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess(CoreProgressManager.java:166)
    at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:627)
    at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:572)
    at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:61)
    at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:153)
    at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit(ProgressRunner.java:233)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1604)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
2021-02-26 12:54:05,279 [6457170]   INFO - ools.idea.run.tasks.DeployTask - Installing application: com.medinq.superlines 
2021-02-26 12:54:05,717 [6457608]   INFO - a.run.tasks.AbstractDeployTask - 284526413ms TRC_BEG [23108][23108] : installer 
2021-02-26 12:54:05,717 [6457608]   INFO - a.run.tasks.AbstractDeployTask - 284526413ms TRC_BEG [23108][23108] : Command Dump 
2021-02-26 12:54:05,717 [6457608]   INFO - a.run.tasks.AbstractDeployTask - 284526413ms TRC_BEG [23108][23108] : get process ids 
2021-02-26 12:54:05,717 [6457608]   INFO - a.run.tasks.AbstractDeployTask - 284526563ms LOG_ERR [23108][23108] : Could not get package user id: run-as: Could not set capabilities: Operation not permitted
 
2021-02-26 12:54:05,717 [6457608]   INFO - a.run.tasks.AbstractDeployTask - 284526564ms TRC_END [23108][23108] :  
2021-02-26 12:54:05,717 [6457608]   INFO - a.run.tasks.AbstractDeployTask - 284526564ms TRC_BEG [23108][23108] : CmdCommand::GetApksFromDump 
2021-02-26 12:54:05,717 [6457608]   INFO - a.run.tasks.AbstractDeployTask - 284526651ms TRC_END [23108][23108] :  
2021-02-26 12:54:05,717 [6457608]   INFO - a.run.tasks.AbstractDeployTask - 284526651ms TRC_BEG [23108][23108] : processing APK 
2021-02-26 12:54:05,717 [6457608]   INFO - a.run.tasks.AbstractDeployTask - 284526651ms TRC_END [23108][23108] :  
2021-02-26 12:54:05,717 [6457608]   INFO - a.run.tasks.AbstractDeployTask - 284526651ms TRC_END [23108][23108] :  
2021-02-26 12:54:05,717 [6457608]   INFO - a.run.tasks.AbstractDeployTask - 284526651ms TRC_END [23108][23108] :  
2021-02-26 12:54:06,969 [6458860]   INFO - a.run.tasks.AbstractDeployTask - Install successfully finished in 1 s 689 ms.. App restart successful without requiring a re-install. 
2021-02-26 12:54:09,280 [6461171]   INFO - run.AndroidLogcatOutputCapture - startCapture("samsung-sm_a510f-3300376233021439") 
2021-02-26 12:54:49,324 [6501215]   INFO - run.AndroidLogcatOutputCapture - stopCapture("samsung-sm_a510f-3300376233021439") 
2021-02-26 12:54:49,324 [6501215]   INFO - run.AndroidLogcatOutputCapture - stopAll() 
2021-02-26 12:55:27,086 [6538977]   INFO - rationStore.ComponentStoreImpl - Saving appBuiltInServerOptions took 15 ms, PropertiesComponent took 16 ms 
2021-02-26 12:55:27,117 [6539008]   INFO - rationStore.ComponentStoreImpl - Saving Project (name=SuperLines, containerState=ACTIVE, componentStore=C:\Users\Ura\AndroidStudioProjects\SuperLines) ProjectView took 16 ms 
2021-02-26 12:55:37,825 [6549716]   INFO - j.ide.actions.RevealFileAction - Exit code 1 
2021-02-26 12:55:38,340 [6550231]   INFO - rationStore.ComponentStoreImpl - Saving appExportableFileTemplateSettings took 16 ms 

phone 上的 OS 版本(和 Java 版本)是什么?我敢打赌这是一个早期版本,其中可能有一个错误。

每个设备的最大 Java 堆大小不同。您可以通过调用 getMemoryClass 来找出它的大小。如果您的应用程序尝试分配超过此数量的内存,则会抛出 OutOfMemoryError,而不管设备的整体 RAM 情况如何(即使仍有空闲 RAM)。 JVM 将在抛出异常之前调用 GC,但如果 space 不足以释放下一次分配(因为所有分配都已使用或因为它是碎片化的/不连续的),它别无选择,但抛出异常。此堆限制不适用于本机代码,本机代码可能会超过它,具体取决于 OS 可以为您的应用保留多少。

出于调试目的,您可以在清单中设置 largeHeap 属性,但这可能无法解决任何问题。 您可以尝试更逐渐地以增量方式分配/初始化变量,或者将大型数据结构移动到本机端以解决堆限制问题。您也可以将您的应用程序拆分为多个进程,因为堆限制是每个进程的,尽管这在游戏中通常没有用。 但是,在此类内存受限的设备(内存少于 2 GB)上,除了删除功能或使用较低质量的资产之外,您无能为力。尽管我认为 google play 没有这样的过滤器,但您可能希望将可以安装游戏的设备限制为具有最小 RAM 的设备。