当垃圾回收器清除对象时,该对象去哪里了?

3
  1. 垃圾回收程序识别出一个未被Java程序使用的类实例(对象),因此决定消除该对象,因为它在代码中没有被使用。当对象消除发生时,该对象在内存中去了哪里?该对象在内存中到底发生了什么?一般来说,当对象被消除时,计算机如何处理消除?消除的工作原理是什么?
  2. 答:被垃圾回收程序回收后,该对象所占用的内存变为空闲状态,但对象本身仍然存在于系统中。由于内存空间得到释放,新创建的对象可以占用它的位置。可以这样理解,二进制格式中先前对象的1和0序列将被新的1和0序列(新对象)覆盖。
  3. 这些过程在Java或计算机科学术语中的名称是什么?
  4. 答:在Java中,这个过程叫做垃圾回收(Garbage Collection)。在计算机科学中,这个过程通常被称为内存管理或动态内存分配。

1
这些术语是“垃圾”,“内存管理”和“释放”。在维基百科上有详细的文章。 - Andrew Tobilko
4个回答

6

什么都没有发生。

一个对象并不是真正的“生命体”。最终,它只是内存中的字节和一些信息,JVM 保留着 “这个对象是‘活着’的”(被其他活着的对象使用),以及“这里是属于该对象的内存”的信息。

现在,当 GC “收集”对象时,概念上会发生什么:JVM 简单地从其内部数据结构中删除“我有这个对象和内存”的信息。并且很可能,像“x 字节的空闲内存在地址 y 处”这样的信息存储在 JVM 中的某些其他数据结构中。这样,JVM 就知道:之前占用的内存现在可用于为另一个对象重新使用。

这很可能会导致:该内存位置在相当长的时间内保持不变。直到 JVM 需要更多内存,并决定将该“空间”用于不同的目的。


1
实际上,对象是自包含的,它们的存活性仅由引用和类型所占用的内存所暗示,而类型是由对象内部指针确定的。因此,对于已死亡的对象,不需要丢弃任何信息,因为当它变得无法访问时,信息已经被丢弃了。唯一需要实际操作的是将内存添加到可用内存记录中。 - Holger

5
你被普遍使用的“垃圾收集器”这个术语误导了,这是一个错误的名称。 “垃圾收集器”不会收集垃圾。
因此你的问题起始点是错误的:
让我们假设垃圾收集器已经识别了一个类的实例(一个对象) - 它没有被Java程序使用。 因此,垃圾收集器决定消除该对象,因为它在代码中没有被使用。
这两件事都不会发生。 垃圾收集器不会识别单个未使用的对象,也不会“销毁”任何对象,因为对象的销毁并不是一件事情。
垃圾收集器通过确定仍在使用哪些对象来工作,通常是通过遍历所有对象引用,从根集开始,即仍在运行的线程的本地变量和由引导加载程序加载的类的静态字段。
当它知道哪些对象仍在使用时,这些对象之间的空隙就是可回收的内存,无论以前存储了多少对象。 它可能只是将这些内存块添加到可用内存列表中,但大多数现代垃圾收集器将重新定位仍在使用的对象,以获得连续的空闲内存块,以便进行快速分配并防止碎片化。
所以:
那么“收集”对象会发生什么?
收集的对象什么也不会发生。 死亡对象对该过程完全没有影响。
这些过程在Java或计算机科学术语中的名称是什么?
一般术语仍然是“垃圾收集”,即使其字面意义不描述实际过程。 有时它被称为“内存管理”,这更适合,因为通常情况下,内存管理器还负责分配并确定堆是如何组织的。
在典型的实现中,您可以将子任务标识为
标记(跟踪) - 识别仍在使用的对象的过程。
清扫 - 浏览差距,将它们添加到空闲内存列表中或准备它们进行以下之一的处理:
复制 - 将特定内存区域中的存活对象重新定位到新区域,以便源区域在此后完全空闲。
紧缩 - 在相同的内存区域内移动某些存活对象,填充间隙,以便该区域在开头或结尾具有连续的空闲内存。

2
这个对象在内存中实际上会发生什么?一般来说,当对象被消除时,计算机如何处理消除?消除是如何工作的?
内存不会直接归还给操作系统。内存现在可以用于JVM未来对象分配。这意味着没有显式删除,引用对象的内存现在可以自由使用。因为内存分配已经由JVM完成,只有在某些GC中才会将内存归还给系统,其频率/行为也可以通过GC参数明确设置,但这是一个复杂的操作,因为它具有成本。
目前正在进行优化此行为的工作,例如:查看openjdk 12热点工作:https://openjdk.java.net/jeps/346

1

1) 该对象所分配的内存只是被垃圾回收器标记为自由状态。Java在开始时分配了一个连续的内存空间(想象一下在c或c ++中分配一个巨大的指针),当您创建一个对象时,内存管理系统会将其放置在那里(对象x在n和m地址之间分配),当对象被删除时,gc只是将n和m标记为自由。

这个过程更加复杂,但你可以用简单的术语来想象它(你可以阅读关于代和压缩的文章以获得更好的理解:)

2) 简单地说,gc在Java应用程序启动时启动一个线程运行。一些重要的术语:代(地址空间的类型),堆(分配内存的地址空间)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接