开发者

What is a nonmemory resource?

I am reading "Effective Java".

In the discussion about fi开发者_Python百科nalize, 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?


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.


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()


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


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.
  }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜