-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cache the methods to free the native objects, per class #13
Conversation
Thanks for your contribution. I believe this should work, but of course I'd want to be sure before integrating the change. And because this code runs asynchronously and interacts with Java garbage collection, it is difficult to test. I also wonder whether the performance benefit justifies the added complexity of the cache. Did you attempt to measure the benefit? Prior to v2.0, Minie used |
Looking more closely at the diffs, I don't see where |
That would be line 154, in the put call, here public static final Method[] of(Class<?> clazz) {
Method[] methods = methodsByClass.get(clazz);
if (methods == null) {
methodsByClass.put(clazz, methods = generate(clazz));
}
return methods;
}
Not really. It's a bit difficult to test since it's done asynchronously from the main execution of the program, so what you should see is that particular thread working less. I'll see if I can make a JMH benchmark comparing these but I'd be veeeeeeeery surprised if the hash lookup isn't faster than the reflection loop (I mean, you could be hitting exceptions every single time in some cases like the I guess I could make the code a bit simpler by removing the |
Here @stephengold, I created this benchmark to evaluate the difference between caching the static method calls vs reflecting on each of them every time. https://gist.github.com/dustContributor/73bc2823158a833a08dbcc9294a16de3 The code that calls them is basically the same except for a few variations in which I wanted to see the boxing impact since the reflective call is forced to box the arguments in one way or the other. I made a fictional hierarchy (classes at the end A, B, C, etc):
As you can see the reflection path can be 10x slower. With slight differences between how far you go pre-boxing the arguments for the reflective call (3 cases tested: boxing on each call, boxing the ID beforehand and boxing the args array directly). |
Nice work. I'm motivated now. I'll try to include this in the next release. |
Sweet, thanks! |
Hi! While I was inspecting how the native interop worked in this library, I noticed that it worked in a peculiar way when freeing native objects.
There is the weak reference queue that gets emptied by a background thread, but I see it relies on reflection to call the respective freeing methods of the hierarchy of each object that gets freed.
I think it's quite easy to cache this process instead of reflecting and navigating the hierarchy on every single free call. I avoided using computeIfAbsent since it seems you deploy on Java 1.7. I know it's a bit defensive to use a ConcurrentHashMap for the cache since it always is called from the same thread but it seemed appropriate.
I haven't tested this extensively. Just ran the buid/tests on my Linux x64 machine and they passed.
As a note I thiiiink this whole process could be avoided by moving things around a bit, having each object implement a free method instead of relying of reflecting over a hierarchy of static methods. It's just that this change seemed much easier to implement in the meanwhile.
I'm a bit new to git, PRs and so on so sorry for any inconvenience.