【问题标题】:How to profile a cache (guava)如何分析缓存(番石榴)
【发布时间】:2012-04-27 13:16:31
【问题描述】:

我在我的 gwt-webapp 的服务器端使用番石榴的缓存。 但是要正确配置缓存,我需要知道一些“遥测”。首先我需要知道一个缓存条目需要多少内存。 到目前为止,我尝试了 jconsole 和 visualvm。问题是,我不知道在哪里看。我查找了 ConcurrencyHashMap 及其条目,但找不到正确数量的实例。

那么,什么是分析(番石榴)缓存的好方法并且可能是简单的方法?

(目前我还没有准备好购买工具来获得缓存(条目)大小的近似值/平均值)

讨论状态总结: Aaron Digulla 建议使用弱引用并让 Java 来完成管理内存的工作。 但是在previous question 中,人们建议“调整、监控、调整”缓存,因为使用弱引用会出现性能问题。

更新 好的,我的问题可能具有误导性——我不想知道有关缓存或其开销的信息。我想知道给定对象的实例有多大 - 配置缓存(在本例中为番石榴)。我必须回答的第一个问题是:我能否在内存中获取所有实例(100% 命中率)或者这需要多少内存。如果这是可能的,则不需要缓存配置。如果所有对象都会占用太多内存,我必须考虑配置。我希望有一个工具可以说明对象的平均内存占用情况。

【问题讨论】:

    标签: java profiling guava


    【解决方案1】:

    正确的解决方案是调用stats() 方法。缓存使用的内存量几乎无关紧要,尤其是当您查看内存价格时。从 ROI 的角度来看:如果您花费超过几个小时来尝试优化缓存,那么再安装 4GB 的 RAM 会更便宜。

    此外,确定“条目的大小”并不容易。根据您放入缓存的值,单个条目的大小可能会有所不同。您可以尝试在heap dump 中查找LocalCache.LocalLoadingCache 的实例(如果您在build() 中使用CacheLoader)或LocalCache.LocalManualCache

    这应该可以为您提供实例大小的平均值,但不会有太大帮助:大小不是“递归”的,因此它不考虑引用。包含引用的问题是在哪里停止。

    例如,每个类都有一个对类加载器的引用。许多类加载器保留对它们已加载的所有类的引用。如果包括在内,您的实例的大小将相差甚远。

    YourKit 非常擅长这种分析,但正如我上面所说,通常不值得。

    【讨论】:

    • 我只需要配置缓存的大小:给定内存量可以占用多少条目。动态配置缓存似乎是个坏主意:stackoverflow.com/questions/9229006/… 人们建议“正确的做法是仔细选择一个 maxSize,它实质上限制了缓存将消耗的内存总量”和“我们强调经典”调整,监控,调整” - 我被困在“监控”部分
    • 再读一遍我回答的第一句话。
    • 抱歉,我不明白:docs.guava-libraries.googlecode.com/git/javadoc/com/google/… 的哪一部分有助于获取有关内存的信息?最后我想在服务器配置(“可用内存”)中提供一个设置,我的代码应该设置一个使用该内存的缓存大小。
    • 再次:您不需要知道每行需要多少内存。这是 Java,而不是 C++。如果驱逐率太高,要么使用弱引用来防止缓存增长过多,要么向服务器添加更多 RAM。
    • (上面所说的关于“弱”引用的一切似乎实际上都是关于引用。)
    【解决方案2】:

    请参阅this question 以获取JProfiler 的解决方案。

    JProfiler 8 将有一个专用的 Guava 探针。免责声明:我公司开发 JProfiler。

    【讨论】:

    • 我读了这个问题。我只是忘了提到我不想花钱来获得缓存条目大小的近似值/平均值。
    • Ingo,我在哪里可以了解有关此“专用番石榴探针”的更多信息?谢谢!
    • 其实会是一个Guava缓存探测,不过目前只是规划,还没有实现。
    • @Ingo,请注意Cache 的实施几乎肯定会随着时间的推移而改变——如果您正在计划任何特定于实施的工具,请与我们联系。
    【解决方案3】:

    它并不是真正的外部工具,但您可以使用 memory-measurer 之类的工具来记录条目的大小。比如:

    Cache cache = ...
    // copy the entries to avoid measuring the footprint of the "EntrySet view"
    List<Map.Entry<K, V>> entries = ImmutableList.copyOf(cache.asMap().entrySet());
    long memory = MemoryMeasurer.measureBytes(entries);
    logger.trace("Size of %s entries : %s bytes", entries.size(), memory);
    

    您可以每隔几分钟记录一次,然后分析数据。

    我认为有人讨论过提供更好的分析工具来简化 Guava 缓存调整。还提出了“自我调整”缓存的想法。不过,似乎找不到我读到的讨论线程。

    【讨论】:

    • 另一种解决方案是将分析器(jconsole、jvisualvm、yourkit、jprofiler...)指向使用ImmutableList.copyOf(cache.asMap().entrySet()) 获得的缓存条目列表。这使您可以查看每个条目的内存占用情况,而与缓存的数据结构无关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多