
Does the Java VM move objects in memory, and if so - how?Java 虚拟机是否曾经移动内存中的对象,如果是,它如何处理对移动对象的更新引用? 我问是因为我正在探索以分布式方式(即跨多个服务器)存储对象的想法,但出于效率原因,我需要能够在服务器之间移动对象。对象需要能够包含指向彼此的指针,甚至指向远程服务器上的对象。我正在尝试考虑更新对移动对象的引用的最佳方法。 到目前为止,我的两个想法是: 我会对有关这些方法的反馈以及对替代方法的任何建议感兴趣。 参考上面关于遍历堆的评论。 不同的 GC\\'s 做不同的方式。 通常在遍历堆时复制收集器,它们不会遍历堆中的所有对象。相反,他们在堆中遍历 LIVE 对象。这意味着如果它可以从"根"对象访问,则该对象是活动的。 因此,在这个阶段无论如何都必须接触所有活动对象,因为它将它们从旧堆复制到新堆。一旦活动对象的副本完成,旧堆中剩下的要么是已复制的对象,要么是垃圾。此时旧堆可以被完全丢弃。 这种收集器的两个主要好处是它在复制阶段压缩堆,并且它只复制活对象。这对许多系统很重要,因为使用这种收集器,对象分配非常便宜,实际上只是增加一个堆指针。当 GC 发生时,不会复制任何"死"对象,因此它们不会减慢收集器的速度。事实证明,在动态系统中,临时垃圾比长期存在的垃圾要多得多。 此外,通过遍历活动对象图,您可以看到 GC 如何"了解"每个对象,并跟踪它们以在复制期间执行任何地址调整目的。 这不是深入讨论 GC 机制的论坛,因为它是一个不平凡的问题,但这是复制收集器如何工作的基础知识。 分代复制 GC 会将"旧"对象放入不同的堆中,最终收集的频率低于"新"堆。理论是持久对象被提升到老年代并且被收集的越来越少,从而提高了整体 GC 性能。 我很想知道更多关于您的要求。正如另一个答案所暗示的,兵马俑可能正是您正在寻找的。 然而,Terracotta 提供的内容与您所要求的内容之间存在细微差别,因此是我的询问。 不同之处在于,就您而言,Terracotta 不提供对对象的"远程"引用——事实上,在使用 Terracotta 时,RMI、JMS 等的整个"远程"概念完全不存在. 相反,在 Terracotta 中,所有对象都驻留在大型虚拟堆中。线程,无论是节点 1,还是节点 2、节点 3、节点 4 等,都可以访问虚拟堆中的任何对象。 没有需要学习的特殊编程或特殊 API,"虚拟"堆中的对象与本地堆中的对象具有完全相同的行为。 简而言之,Terracotta 提供的是一个针对多个 JVM 的编程模型,其操作与针对单个 JVM 的编程模型完全相同。单独节点中的线程的行为就像单个节点中的线程一样 - 对象突变、同步、等待、通知在节点之间的行为与线程之间的行为完全相同 - 没有区别。 此外,与之前的任何解决方案不同,对象引用是跨节点维护的——这意味着您可以使用 ==。这都是维护整个集群的 Java 内存模型的一部分,这是使"常规"Java(例如 POJO、同步、等待/通知)工作的基本要求(如果你不这样做,这些都不起作用\\' t / 不能在整个集群中保留对象身份)。 所以问题又回到了您身上,以进一步完善您的要求 - 您需要"远程"指针的目的是什么? 您要使用的关键字是"压缩垃圾收集器"。 JVM 允许使用一个,这意味着可以重新定位对象。请查阅您的 JVM 手册以了解您的手册是否如此,并查看是否有任何命令行选项会影响它。 解释压缩的概念上最简单的方法是假设垃圾收集器冻结所有线程,重新定位对象,在堆和堆栈中搜索对该对象的所有引用,并使用新地址更新它们。实际上它比这更复杂,因为出于性能原因,您不希望在线程停止的情况下执行完整扫描,因此增量垃圾收集器将尽其所能为压缩做准备。 如果您对间接引用感兴趣,可以从研究 Java 中的弱引用和软引用开始,以及各种 RPC 系统使用的远程引用。 (实际上)任何垃圾收集系统都必须在内存中移动对象以更密集地打包它们并避免碎片问题。 您所看到的是一个非常庞大而复杂的主题。我建议您阅读现有的远程对象样式 API:.NET 远程处理和更进一步的技术,如 CORBA 任何跟踪引用的解决方案都会因为必须处理分布式系统中存在的所有故障模式而变得复杂。 JVM 不必担心会因为网络切换故障而突然发现它看不到一半的堆。 当您深入研究设计时,我认为很多问题将归结为您希望如何处理不同的失败案例。 对评论的回应: 您的问题涉及以分布式方式存储对象,这正是 .NET 远程处理和 CORBA 解决的问题。诚然,这两种技术都不支持这些对象的迁移(AFAIK)。但是它们都广泛处理对象身份的概念,这是任何分布式对象系统的关键部分:系统的不同部分如何知道他们正在谈论哪些对象。 我对 Java 垃圾收集器的细节并不太熟悉,我确信 Java 和 .NET 垃圾收集器有很多复杂性,以在对应用程序影响最小的情况下实现最高性能。 但是,垃圾回收的基本思想是: 作为此过程的改进,VM 可以执行分代垃圾收集,其中根据对象的"年龄"维护单独的堆。对象从堆 0 开始,如果它们在多次 GC 中存活,则迁移到堆 1 并最终迁移到堆 2(依此类推 - .NET 仅支持 3 代)。这样做的好处是 GC 可以非常频繁地运行堆 0 集合,而不必担心做工作来证明长期存在的对象(最终在堆 2 中)仍然活着(它们几乎可以肯定是) . 还有其他改进来支持并发垃圾收集,以及在调度 GC 时实际执行非托管代码的线程的详细信息,这给这个领域增加了更多的复杂性。 听起来您正在寻找分布式缓存,例如 terracotta 或 oracle\\ 的 java 对象缓存(以前称为 tangersol)。 如果您愿意深入了解,可以查看 JBoss Cache 架构文档并获取一些源代码作为参考。 这与您描述的不完全一样,但它的工作原理非常相似。 这是链接。 http://www.jboss.org/jbosscache/ 我希望这会有所帮助。 |