java - 这种技术会阻止 Java 进行垃圾收集吗?
问题描述
Colt McAnlis 制作了一段非常有趣的视频,介绍如何防止 JavaScript 垃圾收集器降低应用程序的速度
它的要点如下:
- 当应用程序加载时,实例化一个未使用的对象/类池,您的应用程序将来可能需要这些对象/类。
- 当您想实例化一个新对象时,请在池中找到一个未使用的适当类型的对象,获取它并设置其属性。
- 请改用此对象。
- 完成后,将其标记为“未使用”,以便将来的方法可以使用它。
我的问题是这种方法是否也适用于 Java 垃圾收集器,或者它是否更难以规避并且最终会扫描你的整个堆或其他东西。
这主要是一个理论/好奇的事情。我没有任何依赖规避垃圾收集的应用程序正在开发中。
解决方案
从某种意义上说,它会“工作”。但不建议这样做,因为存在一些重大问题。
如果你不正确地实现它,那就是内存泄漏。问题是“池”需要保留对其所有对象的引用。这可以防止然后被垃圾收集。但是,如果应用程序在处理完对象时未能始终将对象标记为“未使用”(例如错误),那么这些对象将永远处于“使用中”状态。
(如果你尝试使用
Reference
对象之类的东西来缓解这种情况,你最终会使用更多的空间,并在 GC 上施加更多的负载。)当 GC 运行时,它必须遍历池中的所有对象,以及它们的所有依赖对象。这比允许物体死亡的工作量更大。(根本不需要扫描年轻的无法到达的对象。)
几次 GC 周期后,池中的对象将被永久保存,因为它们是长期存在的。这意味着它们往往会导致可能会被收集的短期依赖对象被保留,直到旧堆被收集。此外,对永久对象字段的引用分配可能更昂贵,并且可能使年轻空间收集花费更长的时间(因为旧 -> 新引用)。
请注意,您所谈论的对象池类型通常是为了减轻应用程序中过多的 GC 暂停而提出/完成的。在典型的现代 JVM 中,有专门设计用于最小化暂停的 GC。在大多数Java 应用程序中,低暂停收集器是解决此问题的更好选择。(一个例外是高度互动的游戏,任何类型的“滞后”都是不可接受的。)
使用对象池还有其他原因:
- 处理初始化成本非常高的对象。
- 处理需要限制数量的对象。
- 处理与需要适当管理的外部资源相关联的对象。
示例包括线程池、数据库连接池和 HTTP 连接池(在典型 HTTP 客户端库的底层)。在适当的情况下,这些绝对是有益的。
推荐阅读
- flipkart-api - 如何使用卖家列表 API 在 Flipkart 中创建产品?
- c - 如何修复“将'bool'传递给'bool(*)[9]'类型参数的不兼容整数到指针转换”?C
- c++ - 在函数中使用 struct std::map
- c# - 如何获取 customPairing.PairAsync 的实际失败原因?
- javascript - 我的代码 javascript 中的某些内容无法制作三角形
- javascript - 在拆分数组中查找元素位置
- flutter - Dart:变量名后面的问号 (?) 是什么意思?
- java - Print 4 numbers (that are divisible by 3 and 6) before x and store them in an array
- javascript - 为什么我在运行 react js 组件类时收到“no-undef”错误?
- iterm2 - 如何在 iTerm2 中自动执行命令