我有一个关于应用程序的内存消耗的问题我正处于大学发展的早期阶段。当我启动一个扩展作为登录管理器的JFrame的类时,该对象会消耗这么多RAM:
显示此JFrame时,程序在任何给定时间消耗大约42 MB的内存。此JFrame允许用户登录和访问医疗记录系统。当用户登录时,登录管理器不会简单地变得不可见;它被.dispose()函数处理掉。然后启动医疗记录系统。
当启动第二个类(也扩展JFrame)时,程序会消耗这么多RAM:
...在任何给定时间大约66 MB。这是有道理的,因为这个JFrame对象更大并且需要更多变量,导致对象占用更多空间。此JFrame上有一个“注销”按钮,用于处理医疗记录系统JFrame对象,并在按下时创建新的登录管理器JFrame对象。
直观地说,我认为因为医疗记录系统被处理掉了,并且登录管理器是应用程序运行的唯一部分,我的程序的内存消耗将减少到任何给定时间消耗的42 MB内存。事实并非如此。
应用程序的内存消耗保持在66 MB。当我注意到这一点时,我的第一个想法是,也许.dispose()函数并没有真正释放分配给对象的内存,就像我想的那样。如果是这种情况,那么反复登录和退出我的医疗记录系统应该不断增加我的应用程序消耗的内存量,因为创建了越来越多的对象。但是,事实并非如此。
当我登录和退出我的病历系统时,我的应用程序的内存消耗大约为66 MB。我的第二个想法是,也许是因为我的应用程序在运行时一次消耗的最大内存量是66 MB,因此正在运行的Java程序在其生命周期内将保留此内存量,尽管它实际上是否需要66 MB空间与否。然后,如果程序需要,可以再循环使用该空间并再次使用。但是,这似乎不是最有效的做事方式。如果是这种情况,一个程序负责排序数百万个元素的数组,并使用递归算法,如合并排序,占用大量空间,然后将其还给,将被迫保持程序在任何给定时间消耗的最大空间。这会冻结不必要的内存量,看起来似乎不是这样。
我告诉你所有这些,以便你可以知道我是如何思考这些问题的:在创建和处理对象时,Java如何处理内存消耗?这特别适用于我的情况?
答案 0 :(得分:1)
正如一些已经建议的那样,你正在查看错误的数字。基本上,Java使用自己的内存管理,并且无法使用任务管理器或顶级来监视内存消耗的起伏。
只要当前的内存量不足以处理手头的任务并且内存参数(-Xmx)允许它这样做,Java就会分配内存。一旦在Java VM中释放了对象,Java进程就不会释放内存,但VM将保留为下一个对象分配准备的内存。
内存将被垃圾收集器释放。这将由诸如完整内存(或手动System.gc()调用)之类的事件触发。垃圾收集器将识别所有不再可访问的对象并释放它们消耗的空间。在这种情况下,自由意味着:对于新的Java对象,而不是底层操作系统。这就是为什么您通常会在整个Java执行过程中看到内存消耗增加而几乎没有内存减少的原因。 (有一种特殊情况,当Java VM的启发式确定时,它已经分配了太多内存并将其返回给操作系统)
事情仍然比较复杂,因为Java VM在一代人模型中管理内存,其中年轻和旧对象的内存区域彼此分开。对象在年轻空间中分配,并随着每个垃圾收集而变老。在某一点上,物体从年轻空间移动到旧空间。这是垃圾收集效率的问题。至于在正在运行的VM中观察所有这些,我将推荐JVisualVM的提议(虽然我想补充一下,它适用于你的情况只对Visual GC插件有用),但我也会把JConsole放到环中。由于某种原因,我不明白,Oracle删除了监视从JConsole(JVisualVM的前身)到JVisualVM的步骤中区分的旧的和年轻的内存空间的能力。
如果您不了解Java的世代内存模型及其对整体内存消耗的影响,我认为您的研究将会失败。作为一个起点,我建议这篇文章:Understanding the Java Memory Model and Garbage Collection