18

I am reading "Effective Java".

In the discussion about finalize, he says

C++ destructors are also used to reclaim other nonmemory resources. In Java, the try finally block is generally used for this purpose.

What are nonmemory resources?

Is a database connection a nonmemory resource? Doesn't the object for holding the database connection occupy some memory?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vinoth Kumar C M
  • 10,378
  • 28
  • 89
  • 130

4 Answers4

23

Database connections, network connections, file handles, mutexes, etc. Something which needs to be released (not just garbage-collected) when you're finished with it.

Yes, these objects typically occupy some memory, but the critical point is that they also have (possibly exclusive) access to some resource in addition to memory.

Graham Borland
  • 60,055
  • 21
  • 138
  • 179
  • 2
    Yes, the main thing is that these resources are as important, if not more important than memory. – Thanh DK Aug 12 '11 at 09:02
  • I wouldn't say that they are more important. I'd argue that memory is the most difficult to manage and is most likely to have a dramatic, detrimental effect on the rest of the system and hence is the best place to start with managed resources. – nicodemus13 Aug 12 '11 at 13:22
  • Just to be clear - many of those things do occupy memory in their own processes, not just the JVM in which your code is running, in which case "releasing" them from within the JVM will allow the non-JVM memory (amongst other things) to be "freed" as well. – GreenieMeanie Aug 17 '11 at 21:06
5

Is a database connection a non memory resource?

Yes, that's one of the most common examples. Others are file handles, native GUI objects (e.g. Swing or AWT windows) and sockets.

Doesn't the Object for holding the database connection occupy some memory?

Yes, but the point is that the non-memory part of the resource needs to be released as well and is typically much scarcer than the comparatively small amount of memory the object uses. Typically, such objects have a finalize() method that releases the non-memory resource, but the problem is that this finalizers will only run when the objects are garbage collected.

Since the objects are small, there may be plenty of available heap memory so that the garbage collector runs rarely. And in between runs of the garbage collector, the non-memory resources are not released and you may run out of them.

This may even cause problems with only a single object: for example, if you want to move a file between filesystems by opening it, opening the target file, copying the data and then deleting the original file, the delete will fail if the file is still opened - and it is almost certain to be if you only set the reference to the input stream to null and don't call close() explicitly, because it's very unlikely that the garbage collector would have run at exactly the right point between the object becoming eligible for garbage collection and the call to delete()

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
0

Another important peace on Java Automatic Memory Management which touches on some of the essentials.

Bitmap
  • 12,402
  • 16
  • 64
  • 91
  • 1
    It is important to understand the concept, I dont think a useful 21 page document, touching the importance of memory management is too big to mark me down. We've seen cleary in this forum how guys like you with huge reputation likes to bring people down. – Bitmap Aug 12 '11 at 12:53
  • Because I agree on this being VERY important, I'm voting you back up. – MGZero Aug 12 '11 at 13:13
  • 1
    @Bitmap: The question specifically addresses **non** memory resources. It's even in the title. Please indicate which of those 21 pages provides the answer to the question. I can't find any. I've therefore chosen the option "-1 this answer is not useful". Nothing to do with my rep. – MSalters Aug 12 '11 at 13:15
  • @MSalters once you've touched down this document - a conclusion can be made on which resource are memory resource and which is not. – Bitmap Aug 12 '11 at 13:20
  • @Bitmap: That presumes a binary distinction. Either a resource is or is not a memory resource. But the question already had a counter-example with the connection object. (Note that your paper also does not address this mixed case) – MSalters Aug 12 '11 at 13:26
  • @MSalters The document does not need to touch down on database connection resource to make it essential to this question. It clearly spits out the Explicits, the Concepts and the desirable which specify clearly answers the question. I could've answered straight yes but I thought I point out the basics - which is essential to make conclusions out, once understood properly. You might've been right about the standard of the document, but that didnt mean it was too huge for the answer and hence unacceptable. – Bitmap Aug 12 '11 at 14:06
-1

The question is better answered the other way around, in my view- 'why don't I need to release memory manually'.

This raises the question, 'why do I need to release any resources?'

Fundamentally, your running program uses many forms of resources to execute and do work (CPU cycles, memory locations, disk access, etc.). Almost all of these suffer from 'scarcity', that is, there is a fixed pool of any such resource available, if all resource is allocated then the OS can't satisfy requests and generally your program can't continue and dies very ungracefully- possibly making the whole system unstable. The only one that comes to mind that isn't scarce is CPU cycles, you can issue as many of these as you like, you're only limited by the rate at which you can issue them, they aren't consumed in the same sense that memory or file handles are.

So, any resource you use (memory, file handles, database connexions, network sockets, etc.) comes from a fixed amount of such resource (avoiding the word 'pool') and as your program (and, bear-in-mind other programs, not to mention the OS itself) allocates these resources, the amount available decreases.

If a program requests and is allocated resources and never releases them to be used elsewhere, eventually (often soon) the system will run out of such resources. At which point, either the system halts, or sometimes the offending program can be killed abruptly.

Pre-90s, resource management (at least in mainstream development) was a problem that every programmer had to deal with explicitly. Some resource allocation management isn't too hard, mostly because the allocation is already abstracted (e.g. file handles or network sockets) and one can obtain the resource, use it and explicitly release it when it's no longer wanted.

However, managing memory is very hard, particularly as memory allocation cannot (in non-trivial situations) be calculated at design-time, whereas, say, database connexions can feasibly be managed this way. (There's no way of knowing how much memory you will use, it's very difficult/ impossible to know when an allocation of memory is no longer in use). Also, memory allocations tend to hang-around for a while, where most other resource allocations are limited to a narrow scope, often within a single try-block, or method, at most usually a class. Therefore, vendors developed methods of abstracting memory allocation and bringing it under a single management system, handled by the executing environment, not the program.

This is the difference between managed environments (e.g. Java, .NET) and unmanaged ones (e.g. C, C++ run directly through the OS). In C/C++ memory allocation is done explicitly (with malloc()/new and associated reallocation), which leads to all sorts of problems- how much do I need? How do I calculate when I need more/less? How do I release memory? How do I make sure I'm not using memory that's already been released? How do I detect and manage situations where a memory allocation request fails? How do I avoid writing over memory (perhaps not even my own memory)? All this is extremely difficult and leads to memory leaks, core dumps and all sorts of semi-random, unreproducible errors.

So, Java implements automatic memory-management. The programmer simply allocates new a object and is neither interested, nor should be in terms of what or where memory is allocated (this is also why there isn't much in the way of pointers in managed environments):

object thing = new Object();

and that's all that needs to be done. The JVM will keep track of what memory is available, when it needs allocating, when it can be released (as it's no longer in use), providing ways of dealing with out of memory situations as gracefully as possible (and limiting any problems to the executing thread/ JVM and not bringing down the entire OS).

Automatic memory management is the standard with most programming now, as memory management is by far the most difficult resource to manage (mainly as others are abstracted away to some extent already, database connection pools, socket abstractions etc).

So, to answer the question, yes, you need to manage all resources, but in Java you don't need to (and can't) explicitly manage memory yourself (though it's worth considering in some situations, e.g. designing a cache). This leaves all other resources that you do need to explicitly manage (and these are the non-memory resources, i.e. everything except object instantiation/destruction).

All these other resources are wrapped in a memory resource, clearly, but that's not the issue here. For instance, there are a finite number of database connexion you are allowed to open, a finite number of file handles you may create. You need to manage the allocation of these. The use of the finally block allows you to ensure resources are deallocated, even when an exception occurs.

e.g.

public void server()
{
  try
  {
    ServerSocket serverSocket = new ServerSocket(25);
  }
  catch (Exception exception)
  {
     // Something went wrong.
  }
  finally
  {
    // Clear up and deallocate the unmanaged resource serverSocket here.
    // The close method will internally ensure that the network socket is actually flushed, closed and network resources released.
    serverSocket.close();
    // The memory used by serverSocket will be automatically released by the JVM runtime at this point, as the serverSocket has gone out-of-scope- it is never used again, so can safely be deallocated.
  }
}
Vinoth Kumar C M
  • 10,378
  • 28
  • 89
  • 130
nicodemus13
  • 2,258
  • 2
  • 19
  • 31