Home  Memory management  Java equivalent to...  const  new  delete  malloc

Threads Database Profiling Regular expressions Random numbers Compression Exceptions C Equivalents in Java

Java equivalents of malloc(), new, free() and delete

C++ provides a few ways to allocate memory from the heap1:

  • the new operator will allocate and initialise an instance of a particular object or array;
  • the malloc() function, inherited from C, will allocate an arbitrary block of memory which can then be used for any purpose, such as an array or struct.

In either case, C++ also requires the programmer to free up allocated memory once it is no longer needed (or else have a memory leak). The free() function recovers memory allocated via malloc(). The delete keyword deconstructs an object, which could involve some cleanup code in addition to deallocating the memory. To understand the Java equivalents of these various operations, it's worth first seeing a general overview of memory management in the two languages, which we'll do in the next section. Then in the following sections, we'll look at details of each of the four abovementioned operations in turn.

The basics: comparing memory management in C++ and Java

For a C++ program to function correctly, the programmer is effectively required to allocate memory in one of the above ways if it is to escape the function in which it is allocated. For example, the following is incorrect:

// Warning: do not try this at home!
char *makeString() {
  char[] str = "Wibble";
  return str;
}

The problem is that str will be allocated off the stack, and this memory will become invalid (or at least, liable to be overwritten) when the function exits. To correct the above function, we need to make it allocate the space for the string via malloc() (or new):

char *makeString() {
  char *str = (char *) malloc(200);
  strcpy(str, "Wibbly");
  return str;
}

It would then be up to the caller to call free() on the resulting string as and when it had finished with it. Things pretty much have to be this way in C/C++: in all but the most trivial cases, it would be virtually impossible for the compiler to determine that an object was "finished with". (Consider, for example, that in C/C++ any pointer could be made to point to that object at some arbitrary moment.)

In Java, things are a little different. The JVM sees Java objects as "objects", not simply as accesses to memory locations. And indeed, Java doesn't allow access to any memory that isn't part of an object. If there are no more references to a particular object, the Java Virtual Machine (JVM) knows that there won't be some pointer lurking about waiting to access that object's memory space. This all means that in Java, memory allocation can be managed much more by the runtime system:

  • the JVM can work out whether an object escapes the method or not, and so the JVM can decide where to allocate the memory (stack, heap, possibly even registers...);
  • the JVM can handle garbage collection: that is, it can work out when an object is no longer referenced and can thus be "deleted";
  • Java basically has no such thing as a pointer2 in the true sense: all objects are accessed by a reference, but this is not an actual memory location.

We've said that the JVM can decide to allocate memory for an object on the stack (if it determines this is safe and desirable). But this is really an implementational detail. In terms of how it looks to the programmer, in Java, all objects are effectively allocated from the heap.

Next: functions and operators

With this introduction in mind, we'll look at the effective equivlents of the C++ memory management keywords and functions mentioned:

  • the new operator in C++/Java;
  • the Java equivalents of the delete operator;
  • how to do a malloc() in Java— is that even possible...?

1. A heap is a block of contiguous memory set aside that can have smaller portions of it allocated out as and when necessary. In the eyes of the programmer, in both C/C++ and Java, we usually talk about allocating from "the heap" in an abstract way. But in neither language is there usually one single block of contiguous memory from which all allocations are made. For performance reasons, good malloc() implementations will internally manage several heaps (e.g. one for large allocations, one for small allocations...); and modern JVMs often have several heaps internally. In most of this discussion, we'll continue to use the term "the heap", as that is how memory is presented to the programmer.
2. The only slight exception in Java is that using the Java Native Interface (JNI), it possible to wrap a direct ByteBuffer around a block of memory allocated from native code (whose address is thus known). But the memory address still isn't exposed at the Java level, and from Java, the memory must still be accessed via that ByteBuffer object.


Written by Neil Coffey. Copyright © Javamex UK 2008. All rights reserved.