你/你如何明智地选择节省CPU和内存?

时间:2014-03-09 20:59:03

标签: java data-structures cpu-usage cpu-speed

我理解JVM会为你优化一些东西(目前还不清楚哪些东西),但是我可以说我会这样做:

while(true) {
     int var = 0;
}

会做:

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

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

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

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

2 个答案:

答案 0 :(得分:2)

别。 Premature optimization is the root of all evil

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

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

如果您发现某些测试用例效果不佳,请调查原因。测量测试用例的各个部分,看看时间在哪里。放大花费大部分时间的部分。

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

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

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

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

  1. 密切关注I / O

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

  2. 优化SQL查询

    如果不注意,SQL查询会为程序的执行时间增加几秒甚至几分钟。所以仔细想想那些。再次,基准他们。您可以编写非常优化的Java代码,但如果它首先花费十秒钟等待数据库运行某些怪物SQL查询,那么它永远不会很快。

  3. 使用正确的馆藏

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

  4. 不要编写代码

    当表现真的很重要时,从某些代码中挤出最后一滴'掉落'本身就成了一门科学。除非您正在编写一些非常奇特的代码,否则很可能会有一些库或工具包来解决您的问题。它将被现实世界中的许多人使用。试过并测试过。不要试图击败那些代码。使用它。

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

答案 1 :(得分:2)

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

然而,有些情况下可读性的提高也伴随着性能的提高。

例如,

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

实现完美,而不是在没有任何补充的时候,但是什么时候没有什么可以带走。 -   Antoine de Saint-Exupery,   法国作家(1900年至1944年)

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

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

但是,如果你找到一个更简单,更优雅的问题解决方案,这值得包括,不是因为它可能更快(认为可能),而是因为它应该使代码更容易理解和维护,这通常是更有价值的利用你的时间。成功使用的软件的维护成本通常是开发成本的三倍。做什么会使穷人的生活变得更容易理解为什么你做了更容易的事情(如果你没有出于任何正当理由这样做更难),因为这可能是你有一天;)

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