代码设计:性能与可维护性

语境化

我正在测试上下文中使用soot框架实现字节码指示器,我想知道哪个设计更好。

我正在为我正在检测的类中的每个方法构建TraceMethod对象,并且我想在多个类上运行此指令器。

哪个选项提供更高的性能(时空)?

选项1 :(地图)

public class TraceMethod { boolean[] decisionNodeList; boolean[] targetList; Map<Integer,List> dependenciesMap; Map<Integer,List> decisionNodeBranchDistance; } 

选项2 :(对象)

 public class TraceMethod { ArrayList targets = new ArrayList(); ArrayList decisionNodes = new ArrayList(); } public class DecisionNode { int id; Double branchDistance; boolean reached; } public class Target { int id; boolean reached; List dependencies; } 

我自己实施了选项2 ,但我的老板建议我选择1 ,他认为这是“更轻”。 我在本文“ Class Object vs Hashmap ”中看到,HashMaps使用的内存多于Objects,但我仍然不相信我的解决方案( 选项2 )更好。

它是一个简单的细节,但我想确定我使用的是最佳解决方案,我关心的是性能(时空)。 我知道第二种选择在可维护性方面更好,但如果它不是最优的,我可以牺牲它。

方法1具有更快速且使用更少空间的有效性。

特别是对于字节码指示器,我首先实现方法1。
然后当它工作时,将两个列表替换为使用原始类型而不是Integer和Double对象的非generics列表。

注意,int需要4个字节,而Integer(Object)需要16到20个字节,具体取决于机器(PC上16个,android下20个)。

可以用GrowingIntArray替换GrowingIntArray (我已经在Apache的统计包中找到了,如果我记得正确的话),它使用了原始的int。 (或者,一旦你知道内容不能再改变,可能只需用int []替换)然后你只需编写自己的GrowingDoubleArray(或使用double [])

记住collections很方便但速度较慢。
对象使用的空间比基元多4倍。

字节码指示器需要性能,它不是每周运行一次的软件。

最后,我不会用非通用的地图替换那个地图,这对我来说似乎有很多工作要做。 但你可以尝试它作为最后一步。

作为最后的优化步骤:查看列表或地图中有多少元素。 如果它通常小于16(您必须尝试它),您可以切换到线性搜索,这是最快的,对于非常少的元素。 一旦元素数量超过特定数量,您甚至可以使代码智能化以切换搜索算法。 (Sun / Oracle java会这样做,而Apple / ios会这样做)在他们的一些集合中。 但是,最后一步将使您的代码更加复杂。

空间作为例外:
DecisionNode:16为类+ 4(id)+ 20(Double)+4(布尔)= 44 + 4填充,然后是8 = 48字节的下一个倍数。

一般来说,你应该总是去维护,而不是假设的性能。 这有几个很好的理由:

  • 我们倾向于对数组与HashMap之间的速度差异着迷,但在实际的企业应用程序中,这些差异并不足以说明应用程序速度的明显差异。
  • 应用程序中最常见的瓶颈是数据库或网络。
  • JVM在某种程度上优化了代码

由于代码可维护,您的应用程序不太可能出现性能问题。 更有可能的情况是,当你有数百万行无法维护的代码时,你的老板会用光钱。