我怎么知道我的缓存对象使用了多少内存?

时间:2011-06-01 08:59:46

标签: java caching object heap hashmap

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

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

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

  1. 如何查看列表使用的内存量? (我已经使用了我们使用垃圾收集器收集内存并采取差异的方法,但是有很多列表,因此需要花费太多时间)

  2. 如何优化刷新列表?

  3. 感谢您的帮助。

5 个答案:

答案 0 :(得分:2)

  

如何找到列表使用的内存量

  

我如何优化刷新列表。

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

另请查看Guava collections


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

答案 1 :(得分:2)

首先,虽然不想在性能问题上进行概括,但您所看到的问题不太可能完全取决于内存使用,但如果列表很大,则可能会在刷新时发挥作用。大量对象有资格收集。

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

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

  1. 如果您使用地图,请尝试使用不需要加载的密钥,并在错过时执行加​​载。
  2. 一旦加载,只刷新自上次加载数据以来已更改的行,但这显然无法解决启动问题。
  3. 现在所说的一切,我建议你不要首先编写自己的缓存代码。我说这个的原因是:

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

答案 2 :(得分:1)

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

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

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

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

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

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

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

答案 3 :(得分:0)

请注意调用

System.gc()

Runtime.getRuntime().gc()
除非你真的需要这样做,否则

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

答案 4 :(得分:0)

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