dagger icon indicating copy to clipboard operation
dagger copied to clipboard

All providers from all modules are class loaded during ObjectGraph.create

Open jasta opened this issue 12 years ago • 4 comments
trafficstars

All auto-generated providers (Provide<SomeClass>ProvidesAdapter) are class loaded by Dalvik during ObjectGraph.create as a result of the implementation of ModuleAdapter#getBindings:

map.put("com.example.ThingYouNeed", new ProvideThingYouNeedProvidesAdapter(module));

This line of code requires that Dalvik both class load and then invoke <clinit> and <init> for ProvideThingYouNeedProvidesAdapter. Because Dagger invokes the getBindings method for all modules in the graph, this effectively means that there is an up front class load and init penalty for every class in the purview of Dagger.

I believe this can be fixed by simply changing ModuleAdapter to use:

map.put("com.example.ThingYouNeed", "com.example.ProvideThingYouNeedProvidersAdapter");

And then using Class.forName explicitly to get a new instance of the adapter class only when the object instance is requested. However it's unclear whether the Class.forName overhead would not be a net performance loss due to decreased performance versus implicit class loading.

jasta avatar Sep 16 '13 02:09 jasta

I modified Dagger's android-simple example to demonstrate this problem. See: https://github.com/jasta/dagger/commits/master for source, and in particular see dvm-debug.log which shows the instrumented result of Dalvik with LOG_CLASS_LOADING 1 enabled to visualize the provider classes being loaded during ObjectGraph.create.

jasta avatar Sep 16 '13 02:09 jasta

Interesting! Care to submit a benchmark? Caliper is handy.

swankjesse avatar Sep 16 '13 03:09 swankjesse

Perhaps, although I did not select Dagger as my implementation after all so I must admit that my motivation for optimizing it has gone way down since I did this investigation months ago :)

jasta avatar Sep 16 '13 04:09 jasta

If we want to investigate this further we probably should:

  • [ ] backfill test of ModuleAdapterProcessor.generateModuleAdapter(). This will easily help show any codegen differences if we take any action here. We can do this similarly to InjectAdapterGenerationTest.
  • [ ] add a caliper test module, which first benchmark could be written to show the time to ObjectGraph.create with 1000 bindings? (what's the best count here?)
  • [ ] figure out a bench for Dalvik, presuming there's not a direct correlation there..

This should be done after @cgruber recent pull requests are merged, but they can be done independently by folks. Once these are in, we have a solid place to test ideas including the class.forname thing that might be promising. I'd be hesitant to do too much before, though. my 2p anyway.

Looking at this realistically, I can't promise I can run through all of this, but I will start on backfilling the generation test tomorrow.

codefromthecrypt avatar Nov 09 '13 21:11 codefromthecrypt