Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does running a single threaded Java program result in many cores active?

I was benchmarking the total delay casting to datatype from Object will have. But I encountered a very weird behavior of a Java collection, in this case, a List.

List<Long> data = new ArrayList<>();
int SIZE = 50_000_000;

long currentTime = System.currentTimeMillis();
for (int i = 0; i < SIZE; i++) {
    data.add(currentTime++);
}

When running the above code the CPU Utilization on my Intel i5 8250u (4 cores) the CPU utilization was 100% running on IntelliJ Idea. So I thought it could be because of IntelliJ, hence I move the code to Azure VM (running CentOS 7.4) having 20 Cores and to my surprise, this piece of code ended consuming 1500% CPU (result from top command) which is 15 cores.

What I'm not able to understand is this: How can a single-threaded Java program code consume more than 1 core?

EDIT:

Steps to Reproduce:

Run the above code.

Machine Configuration:

Laptop: 4 Cores 16Gb RAM, Oracle Java 1.8_161

Azure VM: 20 Cores 148GB RAM, Oracle Java 1.8_161

Output From JVisualVM on Laptop:

enter image description here

enter image description here

like image 478
Saif Ahmad Avatar asked Jul 30 '21 07:07

Saif Ahmad


1 Answers

Your test does nothing but allocating memory. So it quickly exhausts initial heap memory, causing Full GC to run. The heap then increases, but it gets filled quickly again, causing another Full GC, etc.

$ java -XX:+PrintGC Test
[GC (Allocation Failure)  27648K->20757K(104448K), 0.0296779 secs]
[GC (Allocation Failure)  48405K->40538K(132096K), 0.0293287 secs]
[GC (Allocation Failure)  83084K->82453K(138752K), 0.0615143 secs]
[Full GC (Ergonomics)  82453K->75113K(225792K), 0.5392036 secs]
[GC (Allocation Failure)  124981K->139346K(254464K), 0.0563272 secs]
[Full GC (Ergonomics)  139346K->112504K(353792K), 0.5240216 secs]
[GC (Allocation Failure)  185709K->208841K(380416K), 0.0864858 secs]
[Full GC (Ergonomics)  208841K->168513K(512512K), 0.9035611 secs]
...

So, what you observe is a series of long Full GC cycles. The default garbage collector in JDK 8 is Parallel, with the number of parallel GC threads equal to the number of CPUs.

If you run async-profiler in threaded mode (-t), you'll find that almost all CPU time is spent running garbage collection in multiple threads.

CPU profile

like image 181
apangin Avatar answered Oct 22 '22 13:10

apangin