【问题标题】:Is it better to store value as variable or call method again?将值存储为变量还是再次调用方法更好?
【发布时间】:2011-03-23 22:41:19
【问题描述】:

最近,我开始学习一些 Java。从我已经了解的关于 JVM 的知识来看,JIT 使它在需要 CPU 周期的操作(即调用方法)上变得非常快,但也使得它对内存的需求很大。因此,当我需要与以前相同的方法获得相同的输出时,将之前的输出存储在变量中并再次使用它通常是更好的方法 - 同时一直将其保存在内存中 - 还是再次调用相同的方法?

【问题讨论】:

标签: java memory-management jvm jit


【解决方案1】:

最好将输出保存在变量中,而不是再次调用函数。只要需要,该变量就会一直保存在内存中。之后,自动垃圾收集将负责将其从内存中释放出来。但是如果你调用这个函数,它会在每次被调用时占用它的激活记录堆栈的内存。因此,如果您希望您的程序不占用大量内存,最好将结果存储在一个变量中并在需要的任何地方使用它。

【讨论】:

  • 如果一个函数为每次调用返回一个新创建的对象,这意味着垃圾收集器需要做更多的工作。
  • 此外,方法中的任何和所有变量每次都会创建一个新的副本。 addNumbers(int x, int y) { 返回 x+y;每次调用该方法时都会创建两个新变量(它不会重用旧变量,而是创建新变量)。所以如果你调用它两次,那就是 4 个变量。如果你调用它一次并存储答案,那就是 3 个变量。因此,存储它使用更少的内存和更少的 CPU,因为计算只需要进行一次。
【解决方案2】:

据我了解,这是在问哪个更好

Bar bar = foo.getBar();
bar.donkey();
...
bar.kong();

foo.getBar().donkey();
...
foo.getBar().kong();

除非getBar 很昂贵,否则不太可能存在显着的性能差异。同样,内存也不太可能成为问题。专注于可理解性。

意见不一。

我相信 Martin Fowler 更喜欢后者。代码是独立的,而且可能更容易重构。

我认为重构服务于可理解性的目的。前者告诉我,两个调用中使用的对象确实有一个共同的来源,作为奖励,它是什么 [type]。它通常更明确,虽然更冗长,但内容更少。

另一方面,您可能希望将其转换为:

foo.donkey();
...
foo.kong();

【讨论】:

  • +1 - 在没有证据表明两次调用“getter”的潜在效率低下实际上很重要,可读性和正确性应该被视为更重要。请记住,对于一个简单的 getter,JIT 编译器通常可以内联,在这种情况下,只需要 2 或 3 个本机指令。
  • 这里引用了 Fowler 的“重构:改进现有代码的设计”(第 21 页)的一段话:“我喜欢尽可能地摆脱诸如此类的临时变量。临时变量通常是个问题因为它们会导致大量参数在不需要时被传递。您很容易忘记它们的用途。它们在长方法中特别阴险。当然要付出性能代价; ...现在计算了两次。但是很容易优化...当代码被正确分解时,您可以更有效地优化”。
【解决方案3】:

创建一个临时变量不太可能更慢

不过,更重要的是:将返回值存储在变量中可以提高代码的可读性和可维护性。例如:

Biz nibb = getBiz();
frobnicate(nibb.foo(), nibb.bar());
galuncify(nibb.bar());

如果我决定应该使用nibb.biz() 的值而不是nibb.bar(),我必须记住在两个 的地方替换它。如果我改用变量,则不会出现此问题:

Biz nibb = getBiz();
Bar bar = nibb.bar();
frobnicate(nibb.foo(), bar);
galuncify(bar);

还要注意方法调用如何变得更具可读性。

【讨论】:

  • 我认为这个答案根本没有解决他的问题。想象一系列“如果年龄 > 100,如果年龄 > 75”的陈述。假设年龄是通过一种方法检索的,则执行 'if guy.getAge() > 100, guy.getAge() > 75' 等。 内存/cpuwise 比首先执行 'age = guy.getAge()' 更好或更差,并且用那个?
  • 问题是哪种方法“通常更好”。 CPU周期在这种情况下通常不是问题,速度问题不知道机器和JRE就无法回答,甚至只能通过测试来回答,整个事情只是过早的微优化的情况无论如何。
【解决方案4】:

有很多因素,包括个人品味、方法的昂贵程度、方法所做的修改等。

  • 对于基本的 JavaBean/map/list 获取方法,我通常会调用两次以提高可重复性,但这是个人喜好。与方法相同的东西
  • 对于返回值的更昂贵的操作(IE URL 内容),最好进行存储,因为上网、获取数据并返回报告是一项耗时的操作
  • 如果该方法在获取数据时修改了 ANYTHING,我会存储该值

【讨论】:

    【解决方案5】:

    不幸的是,答案几乎可以肯定是“视情况而定”。在时间/内存权衡很重要的几乎所有情况下,您都希望根据证据而不是直觉来采取行动。

    也就是说,使用真实数据测量程序的时间和内存配置文件。即使是相对琐碎的代码,也很难计算出对内联、JITing、缓存未命中等的相对影响。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-26
      • 1970-01-01
      • 2015-11-21
      • 2014-10-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多