Continued from our introduction to memory management operators in C/C++ and Java.html
If you've read the previous page on memory management and new in Java, you may be wondering why the current section on malloc() even exists. We've just stated that in Java, all memory has to be accessed via well-defined objects. In C/C++, on the other hand, malloc() gives us a pointer to an arbitrary block of memory. And in Java, there's no such thing, right?java
Well, strictly speaking this is true: there isn't a way in Java to access "raw" memory via its address (pointer)— at least, not in a way where the address is visible to your Java program. But Java does provide the following rough equivalents to an area of memory allocated via malloc():api
So, for example, the equivalent of the following C code:app
unsigned char *memarea = (char *) malloc(200); *(memarea + 10) = 200; *((int *) (memarea + 16) = 123456; ch = memarea[4];
would be something along the following lines in Java, using a NIO ByteBuffer object:ide
ByteBuffer bb = ByteBuffer.allocate(200); bb.put(0, (byte) 200); bb.putInt(16, 123456); int ch = bb.get(4) & 0xff;
Notice a subtlety of buffer access in Java is that we must deal with sign conversions ourselves. To read an unsigned byte from the ByteBuffer, we must store it in an int (or some primitive big enough to handle values between 128 and 255— basically, anything but a byte!), and must explicitly "AND off" the bits holding the sign.flex
Note that in Sun's JVM— and probably other JVMs with a good JIT compiler— accesses to ByteBuffers usually compile directly to MOV instructions at the machine code level. In other words, accessing a ByteBuffer really is usually as efficient as accessing a malloced area of memory from C/C++1.ui
In the above example, the byte buffer would actually be "backed" by an ordinary Java byte array. It is even possible to call bb.array() to retrieve the backing array. An alternative that is perhaps closer to malloc() is to create what is called a direct ByteBuffer in Java: a ByteBuffer that is backed by a "pure block of memory" rather than a Java byte array2. To do so requires us simply to change the initial call:this
ByteBuffer bb = ByteBuffer.allocateDirect(200);
Note that from Java, we still don't see or have control over the actual memory address of the buffer. Direct byte buffers have the advantage ofaccessibility via native code: although the address is of the buffer isn't available or controllable in Java, it is possible for your Java program to interface with native code (via the Java Native Interface). From the native side, you can:spa
This very last point is quite significant, as it effectively allows things like device drivers to be written in Java (OK, in "Java plus a couple of lines of C" at any rate...).code
Note, however, that you generally shouldn't use direct ByteBuffers "by default":
See also:
Memory usage in Java
Querying the memory usage of an object
Reducing memory usage of Java Strings
Data compression in Java
1. The same is often true of accessing object fields: the JIT compiler can compile accesses to object fields into MOV instructions that "know" the offset of the field in question.
2. You can actually create buffers backed by other types of primitive array, such as an IntBuffer backed by an int array.
--------------------\
ref: api