0

我了解 JVM 为您优化了一些事情(尚不清楚哪些事情),但可以说我要这样做:

while(true) {
     int var = 0;
}

会做:

int var;
while(true) {
     var = 0;
}

占用更少的空间?由于您不是每次都声明新引用,因此您不必每次都指定类型。

while我知道如果我想在该循环之外使用它(而不是像第一个示例中那样只能在本地使用它),您真的只需要将 var 放在外面。另外,对象呢,在那种情况下原始类型会有所不同吗?我知道这是一个小情况,但是这种东西的堆积会导致我的应用程序占用大量内存/cpu。我正在尝试使用尽可能少的操作,但我并不完全了解幕后发生的事情。

如果有人可以帮助我,甚至可以将我链接到可以通过减少操作量来了解节省 CPU 的地方,我将不胜感激。请不要书(除非它们是免费的!:D),现在没有办法获得/:

4

2 回答 2

2

不。过早的优化是万恶之源

相反,编写您的代码,因为它在概念上最有意义。认真写,是的。但是不要认为你可以成为一个“人类编译器”并优化并仍然编写好的代码。

一旦您编写了代码(或多或少,取决于您的经验水平),您就可以为它编写性能测试。尝试考虑可以使用代码的不同方式(连续多次,从前到后或反向,许多并发调用等)并尝试在测试用例中涵盖这些。然后对您的代码进行基准测试。

如果您发现某些测试用例表现不佳,请调查原因。测量测试用例的各个部分以查看时间的去向。放大花费最多时间的部分。

大多数情况下,您会发现奇怪的循环,在再次阅读代码时,您会认为“以这种方式编写它很愚蠢。当然这很慢'并且很容易修复它。以我的经验,大多数性能问题都可以通过这种方式解决,并且几乎不需要“核心优化”。

最后你会发现 99*% 的性能问题可以通过只接触 1% 的代码来解决。其他代码永远不会发挥作用。这就是为什么您不应该“过早”优化的原因。您将花费宝贵的时间优化最初没有性能问题的代码。并使其在此过程中的可读性降低。

数字当然是组成的,但你知道我的意思:)

Hot Licks 指出这不是一个很好的答案,所以让我用一些好的 ol' 性能提示来扩展这个:

  1. 密切关注 I/O

    大多数性能问题不在纯 Java 中。相反,它们与其他系统交互。特别是磁盘访问速度非常慢。网络也是如此。所以尽量减少它的使用。

  2. 优化 SQL 查询

    如果您不小心,SQL 查询会增加程序的执行时间,甚至是几分钟。所以要非常仔细地考虑这些。再次对它们进行基准测试。您可以编写非常优化的 Java 代码,但如果它首先花费 10 秒钟等待数据库运行一些怪物 SQL 查询,那么它永远不会很快。

  3. 使用正确的集合

    大多数性能问题都与多次做事有关。通常在处理大量数据时。将您的数据放在地图中而不是列表中可以产生巨大的差异。还有针对各种性能要求的专用集合类型。研究它们并明智地选择。

  4. 不要写代码

    当性能真的很重要时,从一段代码中挤出最后一个“滴”本身就成为一门科学。除非您正在编写一些非常奇特的代码,否则很有可能会有一些库或工具包来解决您的问题。它将被现实世界中的许多人使用。尝试和测试。不要试图击败该代码。用它。

我们谦虚的 Java 开发人员是代码的最终用户。我们采用语言及其生态系统提供的构建块并将其连接在一起以形成应用程序。在大多数情况下,性能问题是由于我们没有正确使用提供的工具,或者根本没有使用任何工具造成的。但我们确实需要具体细节才能讨论这些。基准测试为您提供了这种特异性。当识别出慢代码时,通常只需将集合从列表更改为映射,或预先对其进行排序,或从某些查询中删除连接等。

于 2014-03-09T21:13:01.600 回答
2

尝试优化不需要优化的代码会增加复杂性并降低可读性。

但是,在某些情况下,可读性的提高也伴随着性能的提高。

例如,

  • 如果数值不能为空,请使用原语而不是包装器。这更清楚地表明该值不能为空,但也使用更少的内存并减少 GC 的压力。
  • 当您有一个不能重复的集合时使用 Set 。通常使用 List 而实际上 Set 更合适,这取决于您执行的操作,通过降低时间复杂度也可以更快。
  • 考虑使用带有一个实例的枚举作为单例(如果您必须使用单例)这比双重检查锁定更简单且更快。提示:尽量只使用无状态的单例。
  • 编写更简单、结构良好的代码也更容易让 JIT 优化。这就是试图用更复杂的解决方案使 JIT 变得聪明的地方会适得其反,因为你最终会混淆 JIT,而你认为​​应该更快的东西实际上更慢。(而且它也更复杂)
  • 尝试减少在关键部分写入控制台(以及一般的 IO)的量。写入控制台是如此昂贵,对于程序和必须阅读它的可怜的人来说,值得花更多时间来生成简洁的控制台输出。
  • 当您有要添加的元素循环时,请尝试使用 StringBuilder。注意:避免将 StringBuilder 用于一个衬里,而只是一系列 append() 因为这实际上可能更慢且更难阅读。

达到完美,不是在没有什么可以添加的时候,而是在没有什么可以带走的时候。——安托万·德·圣埃克苏佩里,法国作家(1900 - 1944)

开发人员喜欢解决难题,并且有一种非常强烈的诱惑去解决不需要解决的问题。对于拥有长达 10 年经验的开发人员来说,这是一种非常常见的行为(无论如何对我来说都是如此;),大约在这一点之后,您已经解决了最常见的问题,然后您开始选择可以解决问题的最佳/最小解决方案集问题。这是您在职业生涯中想要达到的目标,您将能够在比以前更短的时间内开发出高质量的软件。

如果您想解决一个有趣的问题,请在自己的时间继续解决它,看看它有什么不同,但不要将它包含在您的工作代码中,除非您知道(因为您测量过)它确实会有所作为.

但是,如果您找到了一个更简单、更优雅的问题解决方案,那么值得加入,不是因为它可能更快(认为可能是),而是因为它应该使代码更易于理解和维护,而且这通常更有价值利用你的时间。成功使用软件的维护成本通常是开发成本的三倍。做些什么会让穷人的生活变得更容易,因为这可能有一天会成为你;)

关于何时可能使应用程序变慢以改进推理的一个很好的例子是使用不可变值和并发性。不可变值通常比可变值慢,有时慢得多,但是当与并发一起使用时,可变状态很难证明是正确的,您需要它,因为测试它很好但不可靠。使用并发可以消耗更多的 CPU,因此使用不可变对象的成本更高是一个非常明智的权衡。在某些情况下,使用不可变对象可以让您避免使用锁并实际提高吞吐量。例如 CopyOnWriteArrayList,如果您有较高的读写比率。

于 2014-03-09T22:01:14.137 回答