3

Objects of my class keep information retrieved from external database. There is a column of CLOB type in database, it has 1M size. I don't want objects save that in memory. So I keep in object's field only path to local file where information is saved. But I don't want this file to be persistent. I want it to be deleted after the object is destroyed by garbage collector. How to implement this in Java? I guess my class should extend some other specific class and then override a method where I explicitly delete a file.

UPD: I'm making a dynamic webapp, using Java servlets and Apache Tomcat. This webapp works with external db. Webapp runs on Linux. It has some sort of layered architecture, using domain, stores and servlets. The lifecycle of an object described above is simply duration of invocation of doGet() or doPost() methods in a servlet.

Syb3rian
  • 171
  • 2
  • 14
  • 1
    Short answer: this is something you should avoid in Java if at all possible. See the answers to [this question](http://stackoverflow.com/questions/158174/why-would-you-ever-implement-finalize) for more details. – Sam Estep Feb 13 '16 at 13:44
  • It's not ideal, but you can store a `WeakReference` to all file objects and a reaper thread that periodically cleans up any unused references. As others mention, try to design otherwise. – Henrik Gustafsson Feb 13 '16 at 14:43
  • `WeakReference`s and `System.gc()` (which gives just a hint to garbage collect) should do the trick most of the times. But there is no guarantee – Radu Ionescu Feb 13 '16 at 14:56
  • What's your OS? If it's a POSIX-based one (Unix/Linux), and the Java object you use to access the file keeps the file open, you can just delete the file immediately after you create it. As long as your object keeps the file open, you will still have access to it. And once the file is closed, it will be deleted from disk automatically. Your files will even be cleaned up if power fails - as long as your file system doesn't get corrupted, anyway. – Andrew Henle Feb 13 '16 at 15:08

5 Answers5

2

You're wanting to override Object.finalize. This is discouraged. Why? See https://softwareengineering.stackexchange.com/questions/288715/is-overriding-object-finalize-really-bad

You're encouraged to explicitly clean up the file when you know you're done with it.

Community
  • 1
  • 1
Stephen Ingram
  • 190
  • 1
  • 9
1

Instead of persisting and deleting it yourself, I would use an off heap direct ByteBuffer to store the data. This has a number of advantages.

  • This is not written to disk in the first place.
  • No matter how the application dies, it will be cleaned up.
  • It has very little impact on the heap regardless of size (Only the ByteBuffer proxy is on the heap)
  • You can control how much of these are created.
  • ByteBuffer does use finalise but a more light weight mechanism (which only works for components which don't use IO)
  • if you start to run out of memory, this data will be swapped to swap space with relatively little impact on the heap, GC times or the OS. i.e. dramatically less impact than using the heap and less impact than writing to a file.

e.g.

ByteBuffer bb = ByteBuffer.allocateDirect(1 << 20); // 1 MB.
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    I'd be careful using that on a system that uses memory overcommit (Linux) if there will be a lot of such objects on a busy server with lots of long-lived JVMs running. (Yes, if you're running a busy server with a lot of JVMs that you want to be long-lived, you should have disabled memory overcommit and provided sufficient swap space in the first place, but I digress...) – Andrew Henle Feb 13 '16 at 15:16
  • @AndrewHenle agree that over committing is something you have to be careful about, though ByteBuffer doesn't allow over committing as it touches every page to zero it out, so you can only `allocateDirect` if you have free memory/swap. I have a library; Chronicle-Bytes which allows 63-bit off heap regions and it does support over committing though it's not the default. – Peter Lawrey Feb 13 '16 at 17:20
1

I do not think that for your use case it would be so bad to use a finalise, because it is not so important to release the resource that you are holding as soon as possible.

Having said that, instead of a finalise I would use a "weak set". Every time a new object with a reference to the file is created, you can add it to the weak set. Because it is a weak set, the object will be automatically removed when not in use any more.

You can then have a scheduled job that will delete from the temporary folder all the files that are not in the weak set.

This solution has the cost of periodically check each file in the temporary folder, but this won't be a problem if you won't have thousand of active CLOBs.

The advantage is to be able to control how often the clean is executed.

As a nice side effect, you will also have a list of active CLOBs.

Marco Altieri
  • 3,726
  • 2
  • 33
  • 47
0

From the book Java In A Nutshell:

A finalize method in an object is the opposite of a constructor. While a constructor method performs initialization for an object, a finalizer method performs finalization for the object. Garbage collection automatically frees up the memory resources used by objects, but objects can hold other kinds of resources, such as open files and network connections. The garbage collector cannot free these resources for you, so you need to write a finalizer method for any object that needs to perform such tasks as closing files, terminating network connections, deleting temporary files, and so on.

protected void finalize() throws Throwable {
  // Invoke the finalizer of our superclass
  // We haven't discussed superclasses or this syntax yet
  super.finalize();

  // Delete a temporary file we were using
  // If the file doesn't exist or tempfile is null, this can throw
  // an exception, but that exception is ignored. 
  tempfile.delete();
}
Russell Hankins
  • 1,196
  • 9
  • 17
  • Warning: book is 15+ years old and does therefore not necessarily represent current state of knowledge and technology. – BalusC Feb 13 '16 at 13:55
0

I agree with Stephen overriding finalize() is discouraged as it is unpredictable, and generally unnecessary. never do anything time-critical in a finalize(). Never depend on a finalizer to update critical persistent state. What you can do is retrieve the object on demand from external DB and destroy it when job is done (may be in finally block).

Nitin Prabhu
  • 624
  • 6
  • 10