Home  >  Article  >  Java  >  Which is faster, Java heap or local memory?

Which is faster, Java heap or local memory?

黄舟
黄舟Original
2017-03-20 10:53:321464browse

One benefit of using Java is that you don't have to manage memory allocation and release yourself. When you instantiate an object using the new keyword, the memory it requires is automatically allocated in the Java heap. The heap is managed by the garbage collector, and it reclaims memory when objects go out of scope. But there is a 'backdoor' in the JVM that allows you to access native memory that is not in the heap. In this article, I will show you how an object is stored in memory as a continuous bytecode, and tell you how these bytes should be stored, whether in the Java heap or in local memory . Finally I will give some conclusions on how to access memory from the JVM faster: using the Java heap or local memory.

Use Unsafe to allocate and deallocate memory

sun.misc.Unsafe allows you to allocate and deallocate local memory in Java, just like malloc and free in C language. The memory allocated through it is not in the Java heap and is not managed by the garbage collector, so you need to be responsible for releasing and recycling it yourself when it is used up. The following is a tool class I wrote that uses Unsafe to manage local memory:

public class Direct implements Memory {

    private static Unsafe unsafe;
    private static boolean AVAILABLE = false;

    static {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe)field.get(null);
            AVAILABLE = true;
        } catch(Exception e) {
            // NOOP: throw exception later when allocating memory
        }
    }

    public static boolean isAvailable() {
        return AVAILABLE;
    }

    private static Direct INSTANCE = null;

    public static Memory getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Direct();
        }
        return INSTANCE;
    }

    private Direct() {

    }

    @Override
    public long alloc(long size) {
        if (!AVAILABLE) {
            throw new IllegalStateException("sun.misc.Unsafe is not accessible!");
        }
        return unsafe.allocateMemory(size);
    }

    @Override
    public void free(long address) {
        unsafe.freeMemory(address);
    }

    @Override
    public final long getLong(long address) {
        return unsafe.getLong(address);
    }

    @Override
    public final void putLong(long address, long value) {
        unsafe.putLong(address, value);
    }

    @Override
    public final int getInt(long address) {
        return unsafe.getInt(address);
    }

    @Override
    public final void putInt(long address, int value) {
        unsafe.putInt(address, value);
    }
}

Allocate an object in local memory

Let us convert the following Java The object is placed in local memory:

public class SomeObject {

    private long someLong;
    private int someInt;

    public long getSomeLong() {
        return someLong;
    }
    public void setSomeLong(long someLong) {
        this.someLong = someLong;
    }
    public int getSomeInt() {
        return someInt;
    }
    public void setSomeInt(int someInt) {
        this.someInt = someInt;
    }
}

All we have done is to put the properties of the object into Memory:

public class SomeMemoryObject {

    private final static int someLong_OFFSET = 0;
    private final static int someInt_OFFSET = 8;
    private final static int SIZE = 8 + 4; // one long + one int

    private long address;
    private final Memory memory;

    public SomeMemoryObject(Memory memory) {
        this.memory = memory;
        this.address = memory.alloc(SIZE);
    }

    @Override
    public void finalize() {
        memory.free(address);
    }

    public final void setSomeLong(long someLong) {
        memory.putLong(address + someLong_OFFSET, someLong);
    }

    public final long getSomeLong() {
        return memory.getLong(address + someLong_OFFSET);
    }

    public final void setSomeInt(int someInt) {
        memory.putInt(address + someInt_OFFSET, someInt);
    }

    public final int getSomeInt() {
        return memory.getInt(address + someInt_OFFSET);
    }
}

Now Let's take a look at the read and write performance of two arrays: one containing millions of SomeObject objects, the other containing millions of SomeMemoryObject objects .

// with JIT:
Number of Objects:  1,000     1,000,000     10,000,000    60,000,000
Heap Avg Write:      107         2.30          2.51         2.58       
Native Avg Write:    305         6.65          5.94         5.26
Heap Avg Read:       61          0.31          0.28         0.28
Native Avg Read:     309         3.50          2.96         2.16

// without JIT: (-Xint)
Number of Objects:  1,000     1,000,000     10,000,000    60,000,000
Heap Avg Write:      104         107           105         102       
Native Avg Write:    292         293           300         297
Heap Avg Read:       59          63            60          58
Native Avg Read:     297         298           302         299

Conclusion: Reading local memory across the JVM barrier will be about 10 times slower than reading memory in the Java heap directly, and writing operations will be about 2 times slower. However, it should be noted that since the local memory space managed by each SomeMemoryObject object is independent, the read and write operations are not continuous. Then let's compare the performance of reading and writing continuous memory space.

Accessing a large piece of continuous memory space

This test contains the same test data in the heap and in a large piece of continuous local memory. Then we do multiple read and write operations to see which one is faster. And we will do some random address access to compare the results.

// with JIT and sequential access:
Number of Objects:  1,000     1,000,000     1,000,000,000
Heap Avg Write:      12          0.34           0.35 
Native Avg Write:    102         0.71           0.69 
Heap Avg Read:       12          0.29           0.28 
Native Avg Read:     110         0.32           0.32

// without JIT and sequential access: (-Xint)
Number of Objects:  1,000     1,000,000      10,000,000
Heap Avg Write:      8           8              8
Native Avg Write:    91          92             94
Heap Avg Read:       10          10             10
Native Avg Read:     91          90             94

// with JIT and random access:
Number of Objects:  1,000     1,000,000     1,000,000,000
Heap Avg Write:      61          1.01           1.12
Native Avg Write:    151         0.89           0.90 
Heap Avg Read:       59          0.89           0.92 
Native Avg Read:     156         0.78           0.84

// without JIT and random access: (-Xint)
Number of Objects:  1,000     1,000,000      10,000,000
Heap Avg Write:      55          55              55
Native Avg Write:    141         142             140
Heap Avg Read:       55          55              55 
Native Avg Read:     138         140             138

Conclusion:When doing continuous access, Java heap memory is usually faster than local memory. For random address access, heap memory is only slightly slower than local memory, and when targeting large blocks of contiguous data, it is not much slower.

Final conclusion

Using local memory in Java has its meaning, for example when you want to operate on large blocks of data (>2G) and don't want to use the garbage collector (GC) when. From a latency perspective, direct access to local memory is no faster than accessing the Java heap. This conclusion actually makes sense, because there is definitely overhead in crossing the JVM barrier. This conclusion also applies to ByteBuffer using local or heap. The speed improvement of using local ByteBuffer is not to access these memories, but that it can directly operate with the local IO provided by the operating system

The above is the detailed content of Which is faster, Java heap or local memory?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn