How to explain high Java memory consumption in benchmark

135 views Asked by At

I'm writing a small application which allows users to benchmark programs. Currently I'm analysing the results of some test programs and I am quite surprised by what I am seeing. The PC I am using for the measurements has 16GB RAM. Following are the source code and results for the Monte Carlo Integration algorithm.

This is the C# source code:

private const long Iterations = 100000000;
static void Main(string[] args)
{
    Random rand = new Random();

    int underCurve = 0;

    for (int i = 0; i < Iterations; i++)
    {
        double x = rand.NextDouble();
        double y = rand.NextDouble();

        if (x * x + y * y <= 1.0)
        {
            underCurve++;
        }
    }
    Console.WriteLine(((double)underCurve / Iterations) * 4.0);
}

And here are the C# results:

9785344
9711616
9633792
9691136
9740288
9691136
9768960
9662464
9695232
9662464

Minimum memory consumed = 9633792
Maximum memory consumed = 9785344
Maximum memory consumed = 9704243

This is the Java source code:

private static long Iterations = 100000000;
public static void main(String[] args) {
    Random rand = new Random();

    int underCurve = 0;

    for (int i = 0; i < Iterations; i++){
        double x = rand.nextDouble();
        double y = rand.nextDouble();

        if (x * x + y * y <= 1.0){
            underCurve++;
        }
    }
    System.out.println(((double)underCurve/Iterations)* 4.0);
}

And here are the Java results:

454193152
454152192
454201344
454238208
454098944
454258688
454144000
454135808
454189056
454115328

Minimum memory consumed = 454098944
Maximum memory consumed = 454258688
Average memory consumed = 454172672

This is the code I use to measure the memory consumption of the processes:

private static long MeasureMemoryConsumption(String name, string workingDirectory, String arguments)
{
    Process process = new Process();
    process.StartInfo.WorkingDirectory = workingDirectory;
    process.StartInfo.FileName = name;
    process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.Arguments = arguments;

    long peakMem = 0;
    Thread memMeasuringThread = new Thread(() =>
    {
        while (true)
        {
            try
            {
                process.Refresh();
                peakMem = peakMem < process.PrivateMemorySize64 ? process.PrivateMemorySize64 : peakMem;
            }
            catch (InvalidOperationException)
            {
                //ignore, process didn't start yet
            }
        }
    });

    memMeasuringThread.Start();
    process.Start();
    process.WaitForExit();
    memMeasuringThread.Abort();

    return peakMem;
}

When taking a look at the resource monitor during execution, I can see that while the "Private" value in the resource monitor always stays quite small (around 10 MB), the "Commit" value is huge (~400 MB) for Java programs. This is not the case for the C# version. I suppose this has something to do with the problem, however, in my measuring code I am using the PrivateMemorySize64 property.

My question is, how is it possible that the Java version consumes so much more memory than the C# version, and if it is due to an error on my part, how can I get more accurate measurements?

1

There are 1 answers

0
Jeffrey Zhao On

Memory footprint for small program is always an issue for java applications. If you tried some OJ service like leetcode, you'll see that Java implementations are always has larger memory footprint and longer startup time comparing to C/C++/Python/JS/C#:

enter image description here

Different JVM has different startup arguments (e.g. JRockit: Tuning For a Small Memory Footprint) and maybe you could have a try.

Also I think this answer might explain something.