【问题标题】:How i can know how much memory my cached objects are using?我如何知道我的缓存对象正在使用多少内存?
【发布时间】:2011-09-06 02:51:07
【问题描述】:

我们正在尝试缓存数据库选择的结果(在哈希图中),因此我们不必多次执行它们。并且每当我们更改数据库时,为了获取应用程序中的更改,我们添加了刷新列表功能。

现在我们要获取的列表数量很大,因此从数据库加载选择列表需要花费太多时间。

所以我对这个问题有一些疑问:

  1. 如何知道列表使用了多少内存? (我已经使用了我们使用垃圾收集器来收集内存并获取差异的方法,但是列表很多,因此花费了太多时间)

  2. 如何优化刷新列表?

感谢您的帮助。

【问题讨论】:

  • jconsole 或一些分析工具

标签: java object caching hashmap heap-memory


【解决方案1】:

首先,虽然在性能问题方面不想一概而论,但您看到的问题不太可能完全取决于内存使用,但如果列表很大,这可能会在刷新它们时发挥作用大量对象符合收集条件。

要解决与垃圾收集有关的问题,有一些经验法则,但它总是归结为打破分析器和调整垃圾收集器 - 还有更多关于 here 的内容。

但在此之前,任何数据库加载都将涉及对结果集的迭代,因此您可以进行的最大优化将是减少结果集的大小。有几种方法可以做到这一点:

  1. 如果您使用地图,请尝试使用不需要加载的键,并在未命中时执行加载。
  2. 加载后,仅刷新自上次加载数据后发生更改的行,但这显然不能解决启动问题。

说了这么多,我不建议您首先编写自己的缓存代码。我这么说的原因是:

  1. 所有现代 RDBMS 缓存,因此如果您的查询是高性能的,获取实际结果集不应成为瓶颈。
  2. Hibernate 不仅提供 ORM,而且提供强大且易于理解的缓存解决方案。
  3. 如果您确实需要缓存大量数据集,请使用 Coherence 或类似工具 - 缓存可以在单独的 JVM 中启动,您的应用程序不需要承受负载。

【讨论】:

    【解决方案2】:

    我如何知道列表使用了多少内存

    如何优化刷新列表。

    确保您使用正确的数据收集类型。 看看here

    还可以查看Guava collections


    最后一件事,ignis 非常建议您不要使用System.gc(),这可能是您遇到性能问题的真正原因。 This 就是原因。

    【讨论】:

      【解决方案3】:

      这里有两个问题:发现正在使用的内存量,以及管理缓存。我不确定这两者是否真的密切相关,尽管它们可能是。

      发现一个对象使用了多少内存并不难:一篇优秀的文章可供参考,来自 JavaWorld 的“Sizeof for Java”。它逃脱了整个垃圾收集惨败,其中有很多漏洞(它很慢,它不计算对象而是堆 - 这意味着其他对象会影响你可能不想要的结果等)

      管理初始化缓存的时间是另一个问题。我在一家将数据网格作为产品的公司工作,因此我有偏见;请注意。

      一个选项根本不使用缓存,而是使用数据网格。我为GigaSpaces Technologies 工作,我觉得我们是最好的;我们可以在启动时从数据库中加载数据,并将您的数据作为分布式事务数据存储在内存中(因此您最大的成本是网络访问。)我们有社区版以及功能齐全的平台,具体取决于您的需求和预算。 (社区版是免费的。)我们支持各种协议,包括 JDBC、JPA、JMS、Memcached、地图 API(类似于 JCache)和原生 API。

      其他类似的选项包括 Coherence,它本身就是一个数据网格,以及 Terracotta DSO,它可以在 JVM 堆上分布对象图。

      您还可以查看缓存项目本身:两个包括 Ehcache 和 OSCache。 (再次:偏见。我是创建 OpenSymphony 的人之一,所以我对 OSCache 情有独钟。)在您的情况下,会发生的不是缓存的预加载 - 请注意,我不了解您的应用程序,所以我猜测并且可能是错误的 - 但按需缓存。获取数据时,首先检查缓存中的数据,仅当数据不在缓存中时才从数据库中获取数据,并在读取时加载缓存。

      当然,你也可以看看 memcached,虽然我显然更喜欢我的雇主在这里提供的服务。

      【讨论】:

        【解决方案4】:

        我倾向于使用YourKit 来处理这类事情。它要花钱,但 IMO 值得每一分钱(除了作为客户之外没有任何联系)。

        【讨论】:

          【解决方案5】:

          注意调用

          System.gc()
          

          Runtime.getRuntime().gc()
          

          除非您真的需要这样做,否则这是一个坏主意。您应该让 VM 决定何时释放对象的任务,除非在分析后发现这是使应用程序在客户端 VM 上运行得更快的唯一方法。

          【讨论】:

          • 所以你的意思是这是一个坏主意,除非它不是? (-;
          • 网上有很多文章这么说。这是一个坏主意,除非您已经证明您在特定的应用程序和特定的 VM 上确实需要它。
          • 嗨,我使用垃圾收集器只是为了检查我的代码列表使用了多少内存。因此我们可以针对内存问题采取适当的措施。
          猜你喜欢
          • 2011-11-18
          • 2011-02-03
          • 2011-02-21
          • 2017-01-20
          • 1970-01-01
          • 2014-03-01
          • 2017-05-02
          • 2012-02-17
          • 2020-09-10
          相关资源
          最近更新 更多