Java 代码设计:性能与可维护性 语境化

Java 代码设计:性能与可维护性 语境化,java,testing,software-design,Java,Testing,Software Design,我正在测试环境中使用soot框架实现一个字节码指令器,我想知道哪种设计更好 我正在为要检测的类中的每个方法构建TraceMethod对象,并且我希望在多个类上运行此检测程序 哪个选项提供更高的性能(空间-时间) 备选案文1:(地图) 公共类跟踪方法{ 布尔[]决策节点列表; 布尔[]目标列表; 地图依赖性地图; 地图决策节点距离; } 备选案文2:(对象) 公共类跟踪方法{ ArrayList targets=新的ArrayList(); ArrayList decisionNodes=新的A

我正在测试环境中使用soot框架实现一个字节码指令器,我想知道哪种设计更好

我正在为要检测的类中的每个方法构建TraceMethod对象,并且我希望在多个类上运行此检测程序

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

备选案文1:(地图)
公共类跟踪方法{
布尔[]决策节点列表;
布尔[]目标列表;
地图依赖性地图;
地图决策节点距离;
}
备选案文2:(对象)
公共类跟踪方法{
ArrayList targets=新的ArrayList();
ArrayList decisionNodes=新的ArrayList();
}
公共类决策节点{
int-id;
双分支距离;
布尔到达;
}
公共类目标{
int-id;
布尔到达;
列出依赖关系;
}
我自己实施了方案2,但我的老板建议我选择方案1,他认为这是“更轻”。我在本文中看到“hashmap使用的内存比对象多,但我仍然不相信我的解决方案(选项2)更好”


这是一个简单的细节,但我想确保我使用的是最佳解决方案,我关心的是性能(空间-时间)。我知道第二个选项在可维护性方面要好得多,但如果不是最佳的,我可以牺牲它。

方法1有可能更快,占用更少的空间

特别是对于字节码指令器,我将首先实现方法1。
然后,当它工作时,用非泛型列表替换这两个列表,这些列表使用基本类型而不是Integer和Double对象

注意,一个int需要4个字节,而一个整数(对象)需要16-20个字节,这取决于机器(在PC上16个字节,在android上20个字节)

该列表可以替换为
growingtarray
(如果我没记错的话,我在Apache的统计包中发现了这一点),它使用原始int。(或者,一旦您知道内容不能再更改,就可以用int[]替换) 然后您只需编写自己的GrowingDoubleArray(或使用double[])

记住,收藏很方便,但速度较慢。
对象使用的空间是基本体的4倍。

字节码检测仪需要性能,它不是一个每周运行一次的软件

最后,我不会用非泛型的地图来代替这些地图,这似乎是正确的 我需要做很多工作。但你可以试着做最后一步

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

空格作为示例:
DecisionNode:16对于类+4(id)+20(Double)+4(boolean)=44+4填充到下一个8=48字节的倍数。

一般来说,您应该始终进行维护,而不是假定的性能。对此,没有什么好的理由:

  • 我们往往对数组和HashMap之间的速度差异感兴趣,但在实际的企业应用程序中,这些差异还不足以说明应用程序速度的明显差异
  • 应用程序中最常见的瓶颈是数据库或网络
  • JVM在某种程度上优化了代码

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

这可能是个好问题,因为这不仅仅是关于地图或对象,你有完全不同的数据结构,允许/迫使你以不同的方式访问数据。对于
列表
而言,按id访问对象是O(n),而对于
映射
而言,则是O(1)。wrt打火机:典型的贴图是链表结构中节点对象的75%或更少填充的数组[],每个数组都保留实际的键和值对象。在本例中,整数和双精度对象的列表。对我来说,2看起来更轻,因为你有一个包含
int
和其他内容的对象列表,而不是一个只有
int
封装在
Integer
对象中的列表。99%的时候,正确的答案是编写可读性和可维护性更强的代码,如果您的性能度量告诉您这是一个问题,请重写它。过早优化是万恶之源。@Brian Goetz对于字节码检测仪来说,为性能而设计是个好主意。这很容易使速度提高100倍。@JFPicard已关闭,因为该问题只包含存根代码。请阅读并仔细考虑在推荐代码审查之前的标准。谢谢你的详细回答。在这两种设计:为什么你需要一张地图?如果代码创建节点ID,则可以使用ArrayList。NodeId=数组中的位置。拥有无与伦比的直接访问能力。你问我“可以用固定数组代替ArrayList吗?”答案是肯定的,依赖项在开始时是固定的,但是你建议我使用哪种固定数组?可以是二维基元数组吗?上一个:
Map dependenciesMap现在:
int[]dependenciesMatrix=newint[amountftargets][longerDependencieCount]public class TraceMethod {
    boolean[] decisionNodeList;
    boolean[] targetList;
    Map<Integer,List<Integer>> dependenciesMap;
    Map<Integer,List<Double>> decisionNodeBranchDistance;
}
public class TraceMethod {
    ArrayList<Target> targets = new ArrayList<Target>(); 
    ArrayList<DecisionNode> decisionNodes = new ArrayList<DecisionNode>();
}

public class DecisionNode {
    int id;
    Double branchDistance;
    boolean reached;
}

public class Target {
    int id;
    boolean reached;
    List<DecisionNode> dependencies;
}