java - Java中对象的内存消耗

标签 java object memory memory-management

我对我在大学开发的应用程序的内存消耗有疑问。当我启动一个扩展用作登录管理器的 JFrame 的类时,该对象消耗了这么多 RAM:

enter image description here

显示此 JFrame 时,该程序在任何给定时间都会消耗大约 42 MB 的内存。该 JFrame 允许用户登录并访问医疗记录系统。当用户登录时,登录管理器并不是简单地设置为不可见;而是将其设置为不可见。它是用 .dispose() 函数处理的。病历系统随即上线。

当启动第二个类(也扩展 JFrame)时,程序消耗这么多 RAM:

enter image description here

...在任何给定时间大约为 66 MB。这是有道理的,因为这个 JFrame 对象更大并且需要更多变量,导致该对象消耗更多空间。该 JFrame 上有一个“注销”按钮,按下该按钮会处理医疗记录系统 JFrame 对象并创建一个新的登录管理器 JFrame 对象。

直观上,我认为因为医疗记录系统已被废弃,并且登录管理器是应用程序运行的唯一部分,所以我的程序的内存消耗将下降到在任何给定时间消耗的 42 MB 内存。事实并非如此。

应用程序的内存消耗仍为 66 MB。当我注意到这一点时,我的第一个想法是,也许 .dispose() 函数并没有像我想象的那样真正释放分配给对象的内存。如果是这种情况,那么随着创建越来越多的对象,重复登录和退出我的医疗记录系统应该会不断增加我的应用程序消耗的内存量。然而,事实并非如此。

当我登录和退出医疗记录系统时,我的应用程序的内存消耗保持在 66 MB 左右。我的第二个想法是,也许因为我的应用程序在运行时一次消耗的最大内存量是 66 MB,所以正在运行的 Java 程序将在其生命周期内保留这一内存量,无论它实际上是否需要 66 MB MB 空间与否。如果程序需要的话,这个空间可以被“回收”并再次使用。然而,这似乎并不是最有效的做事方式。如果是这种情况,一个程序的任务是对包含数百万个元素的数组进行排序,并使用递归算法(例如合并排序),该算法会占用大量空间,然后再将其归还,那么该程序将被迫保留程序在任何给定时间消耗的最大空间量。这会卡住不必要的内存量,但看起来情况并非如此。

我告诉你这一切,是为了让你知道我是如何思考这些问题的:当对象创建和释放时,Java 如何处理内存消耗?这对我的具体情况有何影响?

最佳答案

正如一些评论已经暗示的那样,您看到的是错误的数字。基本上,Java 使用自己的内存管理,并且无法使用任务管理器或 top 来监控内存消耗的起伏。

每当当前内存量不足以处理手头的任务并且内存参数 (-Xmx) 允许它这样做时,Java 就会分配内存。一旦 Java VM 中的对象被释放,Java 进程就不会释放该内存,但 VM 会保留该内存,为下一次对象分配做好准备。

内存将被垃圾收集器释放。这将由内存满(或手动 System.gc() 调用)等事件触发。垃圾收集器将识别所有不再可达的对象并释放它们消耗的空间。在这种情况下,免费意味着:对于新的 Java 对象,而不是底层操作系统。这就是为什么您通常会看到整个 Java 执行过程中内存消耗不断增加,而内存几乎没有减少。 (有一种特殊情况,当Java VM的启发式判断时,它已经分配了太多内存,并将其返回给操作系统)

事情仍然更加复杂,因为 Java VM 在分代模型中管理内存,新对象和旧对象的内存区域彼此分开。对象被分配在年轻的空间中,并随着每次垃圾收集而变老。在某一时刻,物体从年轻的空间移到了旧的空间。这是垃圾收集效率的问题。

至于在正在运行的虚拟机中观察所有这些,我会赞同 JVisualVM 的提议(尽管我会补充一点,它对于您的情况仅对 Visual GC 插件有用),但我也会将 JConsole 投入其中。由于某种我不明白的原因,Oracle在从JConsole(JVisualVM的前身)到JVisualVM的步骤中删除了区分老旧内存空间和年轻内存空间的功能。

如果你不理解 Java 的分代内存模型及其对整体内存消耗的影响,我认为你的学习将会失败。作为起点,我建议这篇文章:Understanding the Java Memory Model and Garbage Collection

关于java - Java中对象的内存消耗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46578545/

相关文章:

c - 我需要释放结构中的变量吗?

java - 通过选择源而不是源 Jar 选择 Git 存储库/源目录

javascript - 为什么 Obj2 无法通过 Object.Create() 从 Obj1 中按原型(prototype)找到函数

java - Java 中奇怪的对象/类行为

javascript - 我如何在对象/数组中链接?

c - 填写作为指针传递的 vector (C)

mysql - MySQL 在执行 "select"时如何使用内存?

java - 带有 Spring 4 注解的 404 错误页面配置

java - 如何在 Java 中中断/停止工作线程(非当前线程)

java - 向作业添加条件依赖