Java性能分析,性能调优和内存分析练习

时间:2010-08-04 14:01:31

标签: java optimization memory-leaks profiling performance

我即将使用JProfilerEclipse Tptp.对java应用程序进行研讨会分析,性能调整,内存分析,内存泄漏检测等 我需要一套练习,我可以为参与者提供: 使用该工具来分析发现问题:瓶颈,内存泄漏,次优代码等。我相信有丰富的经验和现实生活中的例子。

  • 解决问题并实施优化代码
  • 通过执行另一个分析会话
  • 来演示解决方案
  • 理想情况下,编写演示性能增益的单元测试

问题和解决方案不应过于复杂;应该可以在几分钟内解决它们,最坏的情况是几小时。 一些有趣的领域:

  • 解决内存泄漏问题
  • 优化循环
  • 优化对象创建和管理
  • 优化字符串操作
  • 解决由并发性和并发性瓶颈加剧的问题

理想情况下,练习应包括未经优化的样本代码和解决方案代码。

3 个答案:

答案 0 :(得分:6)

我试图找到我在野外看到的现实生活中的例子(可能稍有改动,但基本问题都非常真实)。我也尝试将它们聚集在同一场景中,这样你就可以轻松地建立一个会话。

场景:您有一个耗时的功能,您希望对不同的值执行多次,但可能会再次弹出相同的值(理想情况下,创建后不会太长)。一个好的和简单的例子是你需要下载和处理的url-web页面对(对于练习它应该可能被模拟)。

循环:

  • 您想要检查页面中是否弹出任何一组单词。在循环中使用您的函数,但使用相同的值,伪代码:

    for (word : words) {
        checkWord(download(url))
    }
    

    一个解决方案非常简单,只需在循环之前下载页面即可。 其他解决方案如下。

内存泄漏:

  • 简单:你也可以用一种缓存来解决你的问题。在最简单的情况下,您可以将结果放到(静态)映射中。但如果你不阻止它,它的大小将无限增长 - >内存泄漏。
    可能的解决方案:使用LRU映射。最有可能性能不会降低太多,但内存泄漏应该消失。
  • 棘手的一个:假设您使用WeakHashMap实现以前的缓存,其中键是URL(不是字符串,请参阅后面的内容),值是包含URL的类的实例,下载的页面和别的。您可能认为它应该没问题,但实际上它不是:因为值(没有被弱引用)具有对密钥(URL)的引用,密钥永远不会有资格清理 - >好记忆泄漏。
    解决方案:从值中删除URL。
  • 和以前一样,但是url是实习字符串(“如果我们碰巧再次使用相同的字符串,则节省一些内存”),值不会引用它。我没有尝试过,但在我看来它也会导致泄漏,因为被禁用的字符串不能被GC编辑。
    解决方案:不要实习,这也会导致你不能跳过的建议:不要做premature optimization, as it is the root of all evil

对象创建&字符串:

  • 说你只想显示页面的文本(〜删除html标签)。编写一个逐行执行的函数,并将其追加到不断增长的结果中。首先结果应该是一个字符串,所以追加将花费大量的时间和对象分配。你可以从性能的角度来看这个问题(为什么追加速度太快),从对象创建的角度来看(为什么我们创建了很多字符串,StringBuffers,数组等)。
    解决方案:使用StringBuilder获取结果。

并发性:

  • 您希望通过并行下载/过滤来加速整个过程。创建一些线程并使用它们运行代码,但是在一个大的同步块(基于缓存)中执行所有操作,只是“保护缓存免受并发问题”。效果应该是你有效地只使用一个线程,因为所有其他线程都在等待获取缓存上的锁 解决方案:仅围绕缓存操作进行同步(例如,使用`java.util.collections.synchronizedMap())

  • 同步所有微小的代码片段。这应该会破坏性能,可能会阻止正常的并行执行。如果你足够幸运/聪明,你也可以拿出死锁。 这样做的道德:同步不应该是一个临时的事情,在“它不会伤害”的基础上,而是一个深思熟虑的事情。

奖金练习:

在开始时填写缓存,之后不要进行太多分配,但仍然会在某处发生泄漏。通常这种模式不容易捕捉。您可以使用分析器的“书签”或“水印”功能,该功能应在缓存完成后立即创建。

答案 1 :(得分:1)

不要忽略this method,因为它适用于these reasons的任何语言和操作系统。一个例子是here。此外,尝试使用具有I / O和显着调用深度的示例。不要只使用像Mandelbrot这样的小型cpu绑定程序。如果你拿那个不太大的C例子,并用Java重新编码,这应该说明你的大部分要点。

让我们看看:

  • 解决内存泄漏问题 垃圾收集器的重点是插入内存泄漏。但是,您仍然可以分配太多内存,并且在某些对象的“新”中显示为很大一部分时间。

  • 优化循环。
    一般来说,循环不需要优化,除非它们内部完成的很少(并且它们需要很长的时间)。

  • 优化对象创建和管理 这里的基本方法是:保持数据结构尽可能简单。特别是远离通知式尝试以保持数据一致,因为这些事情会消失并使调用树变得非常浓密。这是大软件性能问题的主要原因。

  • 优化字符串操作 使用字符串构建器,但不要使用不会占用大量执行时间的代码。

  • 并发。
    并发有两个目的 1)性能,但此的工作范围允许多个硬件同时启动。如果没有硬件,则无济于事。这很疼。
    2)表达的清晰度,例如UI代码不必担心同时进行大量计算或网络I / O.

在任何情况下,它都不能被强调,在你证明某些东西需要很长时间之前不做任何优化。

答案 2 :(得分:0)

我已经使用JProfiler来分析我们的应用程序。但它没有多大帮助。然后我使用JHat.Using JHat你无法实时看到堆。你必须进行堆转储然后分析它。使用OQL(Object Query Language)是查找堆泄漏的好方法。