Code Design: Performance and maintainability

contextualization

I am implementing a bytecode toolkit using soot in the context of testing, and I want to know which design is better.

I create a TraceMethod object for each method in the class that I use, and I want to run this device for several classes.

Which option offers greater performance (Space-time)?

Option 1: (Cards)

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

Option 2: (Objects)

 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; } 

I implemented option 2 myself, but my boss suggested option 1 to me, and he claims to be β€œlighter.” I saw in this article β€œ Class object versus Hashmap ” that HashMaps uses more memory than objects, but im still not convinced that my solution (option 2) is better.

Its a simple detail, but I want to be sure that I am using the optimal solution, my concern for performance (Space-time). I know that the second option is better in terms of maintainability, but I can sacrifice that if it is not optimal.

+4
source share
2 answers

Approach 1 has the potential much faster and uses less space.

Especially for the byte code toolkit, I would first apply approach 1.
And then, when that works, replace both lists with non-shared lists that use primitive types instead of Integer and Double objects.

Please note that int requires 4 bytes, and Integer (Object) - 16-20 bytes, depending on the machine (16 on PC, 20 on android).

The list can be replaced with GrowingIntArray (I found that in the Apache statistical package, if I remember correctly), which uses primitive ints. (Or maybe just replaced int [] when you know the content can no longer change) Then you just write your own GrowingDoubleArray (or use double [])

Remember that collections are convenient, but slower.
Objects use 4 times more space than primitives.

Byte code tools require performance; it is not software that runs once a week.

Finally, I would not replace non-universal Maps, which seems to me a lot of work. But you can try this as a last step.

As a final optimization step: see how many items are in your lists or maps. If it's usually less than 16 (you should try this), you can switch to a linear search, which is the fastest, for a very small number of items. You can even make your code smart for switching search algorithms as soon as the number of elements exceeds a certain number. (Sun / Oracle java does this, and Apple / ios, to) in some of its Collections. However, this last step will make the code much more complicated.

Space as an example:
DecisionNode: 16 for class + 4 (id) + 20 (Double) +4 (boolean) = 44 + 4 padding until the next multiple of 8 = 48 bytes.

+1
source

In general, you should always go for maintenance, not expected performance. There are several good reasons for this:

  • We tend to get carried away by the difference in speed between the array and HashMap, but in a real enterprise application these differences are not large enough to take into account the noticeable difference in application speed.
  • The most common bottlenecks in the application are in the database or on the network.
  • JVM optimizes code to some extent

It is very unlikely that your application will have performance problems due to supported code. Most likely, your boss will have a shortage of money when you have millions of lines of unreachable code.

+1
source

All Articles