Using the sun.misc.Unsafe class to do crazy stuff with the JVM

The way to “use the pause” is to force the GC to run. Otherwise it’s outside of the programmer’s control. These are contradictory statements.

Note that [icode]System.gc()[/icode] really isn’t the way to force a full GC.

(Expanding on Roquen’s comment: the best way is to attempt to allocate a massive array and catch the OOME)

Cas :slight_smile:

Yeah, I didn’t say “how” because it’s fragile. In theory a compiler can remove anything which doesn’t change the meaning of the program…so it’s possible that some compiler might be able to determine that the try block with allocate really big memory doesn’t do anything and remove the whole thing. So (again) in theory the try block would need to be written in such a way that it’s difficult for the compiler to see that it has no side-effect. The ideal situation would be for Java to acknowledge that programmers actually sometimes know what they are doing and expose a method to force a full-gc.

Something like this?


public class ForceGC {

    private static Random RANDOM = new Random();
    //Read this from somewhere else; e.g. write it to a log if it's not zero
    //this is to avoid the compiler optimizing the array allocation
    public static long irrelevantStateField = 0;

    public static void main(String[] args) {
        gc();

    }

    private static void gc() {
        long[] tooBig = new long[10];
        try {
-           tooBig = new long[Integer.MAX_VALUE];
+          tooBig = new long[Integer.MAX_VALUE - 100];
            tooBig[RANDOM.nextInt()] = RANDOM.nextInt();
        } catch (OutOfMemoryError expected) {
            System.out.println("We have forced GC!");
        }
        irrelevantStateField = tooBig[RANDOM.nextInt(tooBig.length)];
    }
}

Pretty much. Though to avoid the JVM shortcutting GC altogether (a potential optimisation) if you attempt to allocate something that’s larger than the actual max heap size you might want to pick an array size based on what the runtime says is actually possible.

Cas :slight_smile:

You are referring to the header fields that can be added to an array?

I edited my suggestion to take this into account. I also outputted the exception message in the catch block ,and confirmed my original code returned:

Requested array size exceeds VM limit

But the corrected code returns:

Java heap space

Thanks for spotting that!

i use something similar. this is from [icode]it.unimi.dsi.Util[/icode] :

public static void compactMemory()
{
  try
  {
    final byte[][] unused = new byte[128][];

    for(int i = unused.length; i-- != 0; )
      unused[i] = new byte[2000000000];
  }
  catch(OutOfMemoryError itsWhatWeWanted){}

  System.gc();
}

just a hint : this works on hotspot. a VM like excelsior jet does not like that!

In a fun twist, it looks like I’ll actually be basing my new rendering system on unsafe access to JEmalloc and mapped OpenGL buffers to avoid the overhead of ByteBuffer objects being created all the time. I’ve created a “smart” byte buffer class that can expand automatically without generating any garbage using JEmalloc and did some benchmarking putting floats in buffers.

Legend:

N = normal access
S = “smart” access

H = ByteBuffer.allocate(), written to using putFloat(index, float)
D = JEmalloc.je_malloc(), written to using putFloat(index, float)
U = JEmalloc.nje_malloc(), written to using MemoryUtil.memPut***())

Result is in million puts per second. I’m guessing a bit here, but the theoretical maximum of the CPU should be 1 instruction per clock, or 3900MHz (turboing) = 3900 million puts per second. My RAM has a theoretical bandwidth of 19 200 MB/sec (2400MHz DDR3), limiting me to 4 800 million 4-byte floats per second.

Results:

NH: 784.80 Mputs/sec ND: 1898.02 Mputs/sec NU: 2215.86 Mputs/sec SH: 280.56 Mputs/sec SD: 389.86 Mputs/sec SU: 665.76 Mputs/sec

My smart buffer has around 1/4th as much throughput as a raw unsafe performance. =< But, my point is that using direct unsafe access is noticeably faster than going with direct ByteBuffers.

I advise you to read my comments once more. It’s the right time to manage the memory on the native heap, which is up to the programmer.

I know that, it’s just an hint, I’m able to read the Java documentation… “Calling the gc method suggests”.