导航期间内存增加,但堆看起来不错?
Posted
技术标签:
【中文标题】导航期间内存增加,但堆看起来不错?【英文标题】:Memory increase during navigation, but heap looks fine? 【发布时间】:2017-04-03 23:09:13 【问题描述】:我目前正在尝试优化我的应用程序的内存使用情况,我注意到一个对我来说看起来很奇怪的行为,所以我想知道这是否正常。
我在同一页面的不同实例之间执行一系列导航,我检查了垃圾收集器似乎工作正常,因为每次导航后页面实例都被正确销毁,以及 ViewModel 实例和每个 ViewModel 中的模型实例。
但是,在每次导航之后,我都会看到一个恒定的内存使用量增加(在调试和发布模式下都进行了测试)。这是一张快照:
从右边的内存图表可以看到,内存使用量在增加,我启动应用时最大值在108MB左右,在屏幕上达到了127MB 。我的意思是这很好,应用程序运行正常,但我不确定这是否正常。 堆大小似乎小于2MB,那么这些~20MB的已用内存是从哪里来的呢?
堆中最大的对象似乎都是系统对象(除了包含当前用户头像的UserHamburgerButtonViewModel
,这就是它的大小的原因),但无论如何,堆中对象的总大小堆远低于那些 20MB 的内存。
如果我继续导航,我可以看到应用程序在每次导航时或多或少地占用 1MB,堆大小保持不变,但私有内存的总量一直在增加,所以我不知道这里发生了什么。
编辑:作为对@Michał Komorowski 的回应,这里是另一个带有 GC 调用的屏幕截图,问题仍然存在:
感谢您的帮助!
【问题讨论】:
在 UWP 应用中,并非所有内存都由垃圾收集器管理。您的托管堆不会增长,但总内存会增长。这意味着增长发生在非托管内存中,例如Windows 运行时对象。这些是引用计数的,应该被回收。但是那个内存没有被压缩。您看到的可能是非托管内存碎片的结果。或者它可能是真正的内存泄漏。 @Sergio0694 看起来不错。 CLR 可以增加堆大小,你也尝试使用GCSettings.LargeObjectHeapCompactionMode
吗?您还可以将Debug
添加到输出GC.GetTotalMemory(true)
。无论如何,看起来还可以。例如,从 ~120MB 开始的 WCF 服务可能会上升到 300MB 左右,然后一直保持在这个标记上,然后一直略微上升或下降。
【参考方案1】:
在您提供的图片中,我没有看到任何垃圾回收 - 它们由黄色指针指示。换句话说,即使内存中有未使用的对象,它们还没有被收集(释放),这就是内存使用量增加的原因。垃圾收集通常是一个缓慢的操作,不应该太频繁地执行。在正常情况下,它仅在需要时运行。
尝试运行您的应用程序更长的时间,例如几分钟。在某些时候,您应该观察到垃圾回收,并且内存的使用会减少。
如果您不想等待几分钟,您可以再做一项练习,即通过调用 GC.Collect() 方法以编程方式强制 GC。 但是,根据经验,永远不要在生产环境中使用 GC.Collect()。如果您需要这样做,则意味着您的代码有问题。
更新 1
在 诊断工具 窗口中,您有 内存使用情况 选项卡。那里有 Take Snapshot 按钮。在导航之前和导航之后单击它。您应该会看到类似的内容:
在此示例中,您可以看到同时创建了 4000 个附加对象。如果您单击一个链接,您将看到一个新窗口,显示实际创建的对象类型。
【讨论】:
您好,感谢您的回答。我还将编辑我的问题以添加它,但我已经尝试调用 GC.Collect() 和 GC.WaitForPendingFinalizers() 几次,即使在每次导航之后,但它不会改变任何东西,保留的内存每次导航后不断增加 至于您的编辑,我已经尝试使用该快照功能,堆总是有大约 14-15k 项(它们似乎是运行时对象,而不是我自己代码中的项)和大小大约 1-1.7MB,所以不可能。我的意思是堆看起来不错,我不知道增加的内存来自哪里以上是关于导航期间内存增加,但堆看起来不错?的主要内容,如果未能解决你的问题,请参考以下文章
Android RecyclerView:如果不使用“setIsRecyclabe(false)”,则滚动期间内存使用量会增加