finalize() and managing non-memory resources

P

Paul J. Lucas

The Javadoc for Object.finalize() (at least in the 1.4.2 JDK)
says in part:

For example, the finalize method for an object
that represents an input/output connection
might perform explicit I/O transactions to
break the connection before the object is
permanently discarded.

But this isn't really a good thing to use finalize() for in
practice since it might take a very long time for an object's
finalize method to be called (if ever). During that time, it's
possible that the system might run out of file descriptors, or
sockets, or whatever.

You might say, "Well, just call close() explicitly." The
problem with that advice is that it doesn't work in cases where
you want objects to hang around as long as possible -- but no
longer.

For example, if I have some class that uses a file as part of
its implementation and I want to keep them around as long as
possible but still allow them to be reclaimed if memory gets
low, then I would use SoftReferences to the objects.

This works great, but only from a memory perspective. Since
the garbage collector doesn't know anything about file
descriptors (or any other non-memory resource), it's can't know
that garbage collection should be triggered if the number of
available file descriptors (or whatever resource) becomes low.

So what's a good way to handle finite, non-memory resources?

- Paul
 
R

Roedy Green

But this isn't really a good thing to use finalize() for in
practice since it might take a very long time for an object's
finalize method to be called (if ever). During that time, it's
possible that the system might run out of file descriptors, or
sockets, or whatever.

I think finalize is for belt and suspenders stuff to help catch some
of the shutdown you miss by other means.
 
T

Thomas Hawtin

Paul said:
For example, if I have some class that uses a file as part of
its implementation and I want to keep them around as long as
possible but still allow them to be reclaimed if memory gets
low, then I would use SoftReferences to the objects.

This works great, but only from a memory perspective. Since
the garbage collector doesn't know anything about file
descriptors (or any other non-memory resource), it's can't know
that garbage collection should be triggered if the number of
available file descriptors (or whatever resource) becomes low.

So what's a good way to handle finite, non-memory resources?

Keep a collection of cached resources (probably using a LinkedHashMap).
Close a poorly used resource when the collection becomes too large.

Treat memory as a separate issue. A soft cache of object using cached
resources can mark the resource as unused (or decrement usage count)
after the SoftReference pops up on the ReferenceQueue.

I'm guessing that actual resources in practice do not have a large
memory footprint. So probably worrying about freeing them in response to
low memory is counterproductive.

Tom Hawtin
 
I

Ingo R. Homann

Hi,
This works great, but only from a memory perspective. Since
the garbage collector doesn't know anything about file
descriptors (or any other non-memory resource), it's can't know
that garbage collection should be triggered if the number of
available file descriptors (or whatever resource) becomes low.

If a resource is only used locally in an object that should stay in
memory as long as possible, than the resource should only be references
locally from the method, and not be a member of the object:

class Resource {
void close() {...}
void finalize() {
close(); // yes!
}
}

class StayInMemory {
Resource r; // evil
void foo() {
Resource r; // no problem
}
}

Anyhow, if it *needs* to be a member, than it would be evil to close it
to early, because it may be used by another method:

class StayInMemory {
Resource r;
void foo() {
r.doSomething();
r.close(); // evil
}
void close() {
r.close(); // good
}
void finalize() {
close(); // yes!
}
}

In short: I don't see your problem!

Ciao,
Ingo
 
M

Mike Schilling

This works great, but only from a memory perspective. Since
the garbage collector doesn't know anything about file
descriptors (or any other non-memory resource), it's can't know
that garbage collection should be triggered if the number of
available file descriptors (or whatever resource) becomes low.

What Java does for file descriptors (and I'm not saying this is foolproof;
it's not) is to trigger a GC when the FileXXputStream constructor receives
an "out of file descriptors" error. This is intended to collect and thus
run finalize() on any objects that have been abandoned without being closed.
 
P

Paul J. Lucas

Mike Schilling said:
What Java does for file descriptors (and I'm not saying this is foolproof;
it's not) is to trigger a GC when the FileXXputStream constructor receives an
"out of file descriptors" error.

The FileXXputStream constructors aren't even documented to throw
any such error (in case the system really can't reclaim any file
descriptors).
This is intended to collect and thus run finalize() on any objects that have
been abandoned without being closed.

Is this behavior documented anywhere?

- Paul
 
P

Paul J. Lucas

Ingo R. Homann said:
If a resource is only used locally in an object that should stay in
memory as long as possible, than the resource should only be references
locally from the method, and not be a member of the object:

This isn't the case (as I stated originally).
Anyhow, if it *needs* to be a member, than it would be evil to close it
to early, because it may be used by another method:

Yes, I know.
void close() {
r.close(); // good
}

There can't be a close that's useful.
void finalize() {
close(); // yes!
}

This isn't guaranteed to be called -- ever.
In short: I don't see your problem!

Again, the problem is that, despite what the Javadoc for
finalize() says, you really can't rely on finalize() to release
finite resources (or much of anything, really).

- Paul
 
I

Ingo R. Homann

Hi,
There can't be a close that's useful.

Sorry, because you snipped too much, I'm not sure if you are talking
about Reosurce.close() or StayInMemory.close().

Anyhow: It *is* useful! (Maybe, you can call it dispose() :)
This isn't guaranteed to be called -- ever.

I know, but in practice, it works very well and *is* called -- ever.

Ciao,
Ingo
 
P

Paul J. Lucas

Thomas Hawtin said:
Keep a collection of cached resources (probably using a LinkedHashMap).
Close a poorly used resource when the collection becomes too large.

Let's make it concrete by using file descriptors (which is what
I assume things like FileInputStream, RandomAccessFile, etc) use
internally, at least on *nix-like systems.

So, in this case, I have to guess at how many file descriptors I
think there can safely be on any given system and have to write
some kind of, say, RandomAccessFileProxy, that effectively does
caching of file descriptors by putting an aritifical cap on the
number that can exist any any given time.

Somebody explain why Java and garbage-collection is supposedly
such a good thing to me again.
Treat memory as a separate issue. A soft cache of object using cached
resources can mark the resource as unused (or decrement usage count)
after the SoftReference pops up on the ReferenceQueue.

The SoftReference isn't guaranteed to show up on the
ReferenceQueue before the number of file descriptors runs out
because it's not guaranteed that garbage collection will be
triggered before the number of file descriptors runs out.
I'm guessing that actual resources in practice do not have a large
memory footprint. So probably worrying about freeing them in response to
low memory is counterproductive.

Right: they need to be freed in response to "no more file
descriptors" -- but there's no easy way to tell Java to do
that.

- Paul
 
I

Ingo R. Homann

Hi again,
Again, the problem is that, despite what the Javadoc for
finalize() says, you really can't rely on finalize() to release
finite resources (or much of anything, really).

By the way, I thought, your problem was that e.g. the FileHandles go out
of scope and (of course) the GC doesn not do anything to release them:
This works great, but only from a memory perspective. Since
the garbage collector doesn't know anything about file
descriptors (or any other non-memory resource), it's can't know
that garbage collection should be triggered if the number of
available file descriptors (or whatever resource) becomes low.

Anyhow, that can be solved as well. (see Mikes answer)

Ciao,
Ingo
 
P

Paul J. Lucas

Ingo R. Homann said:
By the way, I thought, your problem was that e.g. the FileHandles go out
of scope and (of course) the GC doesn not do anything to release them:

There's no such thing as "out of scope" for Java objects
because they're always created on the heap. The term "scope"
exclusively means a lexical block. References (which are not
objects) can go out of scope, however; but the objects they
referred to most likely still exist afterwards.

- Paul
 
P

Paul J. Lucas

Ingo R. Homann said:
Sorry, because you snipped too much, I'm not sure if you are talking
about Reosurce.close() or StayInMemory.close().

It doesn't matter. The class using the resource does so
internally, so its close() is not exposed to the user. The
class using the resource ideally should hang around a while,
but go away if memory becomes low; hence it's kept via a
SoftReference. Therefore there's no way to tell when any
close() method on it (even if it has one) should be called.
Anyhow: It *is* useful! (Maybe, you can call it dispose() :)

Again, doesn't help.
I know, but in practice, it works very well and *is* called -- ever.

But there's no way to guarantee that it's called before the
finite resource runs out. The garbage collector is *only*
concerned about memory.

- Paul
 
I

Ingo R. Homann

Hi,
There's no such thing as "out of scope" for Java objects
because they're always created on the heap. The term "scope"
exclusively means a lexical block. References (which are not
objects) can go out of scope, however; but the objects they
referred to most likely still exist afterwards.

Sorry, obviously I expressed that wrong (I'm no native speaker as you
might have noticed! :)

I meant that "windows runs out of FileHandles" or "Windows has nor
enough FileHandles left"

Ciao,
Ingo
 
T

Thomas Hawtin

Paul said:
Let's make it concrete by using file descriptors (which is what
I assume things like FileInputStream, RandomAccessFile, etc) use
internally, at least on *nix-like systems.

So, in this case, I have to guess at how many file descriptors I
think there can safely be on any given system and have to write
some kind of, say, RandomAccessFileProxy, that effectively does
caching of file descriptors by putting an aritifical cap on the
number that can exist any any given time.

Somebody explain why Java and garbage-collection is supposedly
such a good thing to me again.

What has that got to do with garbage collection? In C, say, if you
wanted to cache descriptors you'd have to either determine the number of
descriptors available, force release on allocation or guess.
The SoftReference isn't guaranteed to show up on the
ReferenceQueue before the number of file descriptors runs out
because it's not guaranteed that garbage collection will be
triggered before the number of file descriptors runs out.

Yup. That's why I'm suggesting a separate mechanism to keep track of
descriptors.
Right: they need to be freed in response to "no more file
descriptors" -- but there's no easy way to tell Java to do
that.

You don't need to free memory because you have run out of descriptors.
They are, as I said, different issues.

Tom Hawtin
 
M

Mike Schilling

Paul J. Lucas said:
The FileXXputStream constructors aren't even documented to throw
any such error (in case the system really can't reclaim any file
descriptors).

This behavior is internal to the constructor implementation. I presume that
"out of file descriptors" results in an IOException. Let's see: Yes, on
Windows XP I get

java.io.IOException: Too many open files
Is this behavior documented anywhere?

Not that I know of, but I've seen it described so often that I'd call it
common knowledge.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top