I'm instrumenting a Android project for a specific testing purpose. I hope to transfer some information (e.g., an infoObj
object) between method invocations. So the basic idea is to use a map (indexed by thread id to avoid concurrency issues) to store the infoObj
before invoking a method, and then retrieve the infoObj
from the map at the beginning of the invoked method body.
For example, here are two methods f1
and f2
where f1
invokes f2
.
void f1() {
f2();
}
void f2() {
}
After instrumenting, they become:
void f1() {
map.put(threadID, infoObj); // put infoObj into the map before invoking f2
f2();
}
void f2() {
map.remove(threadID); // get infoObj from the map at the beginning of f2
}
It works well in most of the cases. But when method invocations occur in a long loop, the instrumented program runs much slower than its original one. Using parameters to transfer is the best solution but unfortunately I cannot modify method definitions because program semantics may change.
What is the most efficient solution to achieve my goal?
CodePudding user response:
There isn't really a good way of doing this in Java. The main problem is that if you have multiple threads you need a map and maps are moderately expensive to use due to them having to calculate hashes and locate the item in the internal data structures.
Note that HashMap
is also not thread-safe. You haven't said whether you have made it safe (e.g., using Collections.synchronizedMap
). If you have, then you are better using ConcurrentHashMap
which is much faster than a synchronized HashMap
. If you haven't, making it thread-safe will only get worse.
I can suggest a few things:
- You might be able to avoid the issue by predicting which thread you are in. I am not an expert on Android, but quite often certain bits of code can only be in certain threads and there might not be a lot of multi-threading going on unless you initiated it yourself. If that is the case you can just create a specific static for that code-point and reference it directly.
- If you can't avoid using maps, you could scour the internet for faster map implementations.
- Can you do the put operation elsewhere? Writing to a map is the slowest part, so if you can pre-populate it for the thread, that might speed things up. You also don't want to be allocating memory (calling new) in your instrumentation code, so make sure infoObj is pre-allocated and re-use it on each call.