2

I have a long method that consists of about 350 lines. It's a routine method that another method uses in a cycle and it uses it many times (I'm talking here about numbers greater than 100 000).

The routine method has many conditional branches dependent on some computations. The computations in each branch look like this:

...
double cosValue = Math.cos(finalAngle);
double sinValue = Math.sin(finalAngle);
double baFirst_rotated_x = b.getA().getFirst().getxCentroid() * cosValue - b.getA().getFirst().getyCentroid() * sinValue;
...

So the heap space needed is not of a small size. The application works fine, but it's really slow.

Weird thing is that when I add a System call, for example, it runs much faster (like 10x faster). So when I put this

System.out.println("..."); or System.gc();

inside the routine method, it performs better. It looks like the System call somehow unpauses the application. Could someone please give me a hint why this might be happening? I know this is a very indefinite question and I apologise for that. I just think that there must be an explanation of what's actually happening and I can't move on without knowing it.

vaultah
  • 44,105
  • 12
  • 114
  • 143
MartinB
  • 31
  • 1
  • 5
  • Maybe you're taking up too much memory, and the system is starting to swap pages to virtual memory which is reducing speed. And with GC, the unused yet still occupied memory will be free to use. – TwilightSun Feb 16 '14 at 14:34
  • 2
    Are you sure you're benchmarking it correctly? I.e., with warmups or long run times? Correct benchmarking in Java is *hard* because the JVM keeps recompiling the code while it runs. – Boann Feb 16 '14 at 15:10
  • Note, primitives in Java are stored on the stack not the heap. See http://programmers.stackexchange.com/a/65289. – Dave Swartz Feb 16 '14 at 15:12
  • Also, How do I write a correct micro-benchmark in Java?| http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java/513259#513259 – Dave Swartz Feb 16 '14 at 15:14
  • Why did you accept an answer already? You didn't figure out what's happening yet. – Boann Feb 16 '14 at 15:35
  • That's right, but it's helpful. Should I accept only the answers with a solution? What if there is no such answer? Anyways, thank you for responses. I'll have a look at the links. – MartinB Feb 16 '14 at 15:44
  • @Marat It's not wrong; it's just that I'm interested to know the answer too. Although it's almost certainly just a flawed benchmark. – Boann Feb 17 '14 at 13:04
  • I'm still trying to figure it out, however the most probable cause is what you had said - a flawed benchmark. I might had made a conclusion too fast. – MartinB Feb 17 '14 at 22:41
  • Give [*this method*](http://stackoverflow.com/a/317160/23771) a try. – Mike Dunlavey Feb 18 '14 at 16:37

1 Answers1

1

To find the bottleneck, I recommend to try the VisualVM tool that is part of the SDK since Java 6u7. It's ridiculously easy to try, and it seriously helped me to achieve massive improvements on several occasions.

Here's what you do:

  1. Start your application, and get ready to run something that is slow. Don't run it yet, just be ready to start with a click.
  2. Start VisualVM, which should be in $JAVA_HOME/bin/jvisualm
  3. In the Applications tab on the left, find your slow application and double-click
  4. Click on the Sampler tab. When ready, click on the CPU button, then start the slow step in your application, and when the step is finished come back to VisualVM and stop sampling.

Click on Snapshot and examine the threads: look at the Time and Time (CPU) columns. The interesting threads are the ones where Time (CPU) is bigger than 0 and less than Time. Usually you can ignore any AWT and Database threads, and probably other types too, depending on your application. That should leave you with just a few threads to look at. Expand them to drill down to the time consuming methods.

Using this technique, you will have the exact locations where your application is spending its time. And I must say, the results surprised me every time: even in a code full of inefficient code, there are usually just a few pain points that really matter, and they are usually not obvious at all, until you find them with at this tool. Give it a try!

The docs: http://docs.oracle.com/javase/7/docs/technotes/guides/visualvm/

janos
  • 120,954
  • 29
  • 226
  • 236