4

Let's consider following code:

class Table {
 private static int number_of_Tables=0;
 public Table(){
  ++number_of_Tables;
 }
 public void finalize(){
 --number_of_Tables; 
 }
 public static int current_TableCount(){
  return number_of_Tables;
 }
}

What I want to achive is that when GarbegeCollector (GC) destroys the Object that the count of available Objects gets decresed by one.

But everyone here on topic of finalize() is saying that using this method is very bad because following could happen: even though there are no references pointing to the object the GC may not destroy it immediately because GC doesn't work around the clock i.e GC will be invoked after certain amount of object are there to be destroyed i.e at certain times GC will perform the cleanup, which means that even though the object is not available anymore my counter wouldn't decrease and I would give the false information upon invoking the method curret_TableCount()

What do people do instead, to solve this kind of a problem with certainty?

There must be some kind of solution in Java?

EDIT2: I need to recognize when the object is not referenced anymore i.e during runtime there exists not even one pointer(reference) to the object, when this is true, I would then decrese the number of that kind of objects by one.

  • 1
    At least related (if not a dupe): https://softwareengineering.stackexchange.com/questions/333146/static-members-and-finalize – πάντα ῥεῖ Nov 24 '19 at 16:23
  • 4
    Change your question so that it asks about the actual problem you are trying to solve, instead of the method you have chosen to solve it (use your approach only to demonstrate your attempt to solve the problem). See https://meta.stackexchange.com/a/66378 – Robert Harvey Nov 24 '19 at 16:26
  • 3
    `When an Object is not available to the user anymore that the Programm gives the accurate Information to the user about the number of available Items. For example an item that is bought from a store how many items of the same kind are still in the store` -- **Use a collection.** Collections are designed specifically to do this. – Robert Harvey Nov 25 '19 at 16:23
  • As @RobertHarvey has noted, the problem of keeping track of items in a store would not typically indicate this kind of solution. Is that really what you are doing? – JimmyJames Nov 25 '19 at 19:46
  • @JimmyJames no my assignment is to recognize when the object is not referenced anymore i.e during runtime there exists not even one pointer(reference) to the object, when this is true, i would then decrese the number of that kind of objects by one. how this information is going to be further used I don't know – user12394078 Nov 26 '19 at 04:18
  • 1
    Why would you be asked to re-invent the Java garbage collector, poorly? – Robert Harvey Nov 26 '19 at 05:12
  • 1
    Have a look here: https://www.geeksforgeeks.org/object-pool-design-pattern/ – Robert Harvey Nov 26 '19 at 05:12
  • @RobertHarvey well to be fair I am allowed to use finalize maybe they have created some kind of their own GC if that is possible or maybe they are unaware of this problem but since the head of the Team is a PhD guy it is probably not the case that they are unaware , Thanks to everyone for their help so many new stuff to learn – user12394078 Nov 26 '19 at 06:36
  • You've got it backwards. The GC is a tool for [simulating infinite memory](https://devblogs.microsoft.com/oldnewthing/20100809-00/?p=13203) not for doing stuff when an object is no longer accessible. – Caleth Nov 26 '19 at 10:03
  • 1
    You might want to talk to your professor about expectations. PhantomReference probably works for this scenario using Reference queues as I mentioned in my answer. You can attempt to force major collections using System.gc(). If that's not good enough, you'd need start looking at things like agents and/or JMX. – JimmyJames Nov 26 '19 at 15:05
  • @user12394078 `finalize` does that. But the reasons you shouldn't use `finalize` are *because you shouldn't do that because it's a bad idea*. Like, is it okay for your code to return a different count if your server gets a RAM upgrade? – user253751 Nov 27 '19 at 11:00

2 Answers2

6

Depending on your design there are two mechanisms in Java that you can use instead. finalize is to be avoided mainly because it creates performance issues with garbage collection and it possible create new references to the object that is being collected leading to undefined behavior i.e. big problems.

References

ReferenceQueue

If you want to be informed of the collection of an object in Java, the safe way to do that is to use a Reference and register it with a ReferenceQueue. This can be a little confusing to work with because you need to make sure it's the reference that tells you what object was removed, the a reference to actual object that is was collected will not be passed to you. This is to avoid the problem mentioned above with finalize.

WeakHashMap

A similar but perhaps simpler approach to using a Reference for this is to use a 'weak' Map such as WeakHashMap. You can periodically check the Map for what remains and by elimination determine what has been removed.

Potential problem with References

The issue with this in your case is that the object will not be collected immediately after you release all references to it. In fact it may never be collected at all. One scenario could be where you have a small number of medium-to-long-lived objects (including this one) that end up in a tenured generation but everything else is short-lived. The tenured generation never fills up and therefore never gets collected so even if the garbage collector runs, some of your table objects may not be collected.

The upshot is that if you need immediate and/or deterministic counting, you can't rely on garbage collection.

Closeable or AutoCloseable

Another option is to implement the Closeable or AutoCloseable interface. This makes your class available for use in a 'try-with' block like so:

try (Table table = new Table()) {
  /* Do things with table */
}

When the block exits (for any reason) the close method on Table will be executed. This is probably the best possible option if tables exist within the scope of a method. If you are holding these in a structure that lives on the heap and they outlive the method in which they are defined, this won't work for you.

Explicit management

The last option you have is to explicitly call a method when you are no longer using the object.

Pools

A pool allows you to keep track of set of objects. The challenge is that you need to make sure each object get's released from the client-side. If you've ever used a connection pool with database connections, you should know that you need to call close when every you are done using a connection. If you don't, you will end up with a connection leak and the pool can eventually run out of available connections.

Inverted Control

One option I've used to put all the resource management in one place. To give an example of this Consider again the Connection pool example. The common way to use them is to have code all of over the application that requests a Connection and then when it's done, close will be called. This is fine if you use try-with blocks or otherwise guarantee it's being called at the right time. You can avoid the need to do that however with something like this:

class QueryExecutor {
  public void execute(SqlQuery query, ResultSetHandler handler) {
    try (Connection conn = pool.getConnection()) {
      try (Statement stmt = conn.createStatement()) {
        try (ResultSet rs = stmt.executeQuery(query.toString())) {
          handler.process(rs);
        }
      }
    }
  }
}

The advantage here (aside from DRY) is that you have one place to make sure all of this is being done correctly instead of having to worry about all the possible places where a close might have been missed.

JimmyJames
  • 24,682
  • 2
  • 50
  • 92
  • See the edit the OP made to their question 23 hours ago, and my response in the comments below the OP. – Robert Harvey Nov 25 '19 at 16:25
  • @RobertHarvey Doesn't seem helpful. – JimmyJames Nov 25 '19 at 17:28
  • Well, the description the OP provided describes a *collection.* Granted, the description is rather abstract. – Robert Harvey Nov 25 '19 at 17:39
  • 1
    @RobertHarvey I get where you are going but the attempt to use finalize() for counting objects or other purposes, anything at all really, is a pretty disastrous approach in Java. It's also somewhat unfortunately common especially for people coming from a C++ background. I think a description of the alternatives is useful even if that's not what the OP really needs. – JimmyJames Nov 25 '19 at 17:42
  • Isn't an ordinary collection one of the alternatives? – Robert Harvey Nov 25 '19 at 19:03
  • @RobertHarvey To using `finalize()`? I'm struggling to make that leap. If you are using a pool, it's probably implemented with one or more collections. I suppose you could use a collection as a pool but it's more clear to just say pool. – JimmyJames Nov 25 '19 at 19:44
  • I claim that the use of Finalize here is an [X Y problem](https://meta.stackexchange.com/a/66378/102937). – Robert Harvey Nov 25 '19 at 21:15
  • @RobertHarvey It's possible but it seems to me the rest of the question doesn't align with the example given. I've asked the OP for clarification. – JimmyJames Nov 25 '19 at 21:36
3

Instead of relying on the gc to call finalize(), a manual 'convention' of calling close(), or something similar to C#'s language supported using and Dispose() (which is still a convention requiring manual use of the pattern) you can use a procedure which accepts a single method interface (or C# delegate) and calls its method with the resource to manage (or object to count):

interface IFrobstinatorUser<T>
{
    T use(Frobstinator toUse);
}

class FrobstinatorProvider
{
    public T withFrobstinatorDo<T>(IFrobstinatorUser<T> client)
    {
        // Do everything required before a Frobstinator can be used.
        // For example: incrementing the count of Frobstinators that are in use.
        try
        {
            Frobstinator item = new Frobstinator();
            T result = client.use(item);
            // If needed, we can do something here with item after client is done use it and returns normally
            return result;
        }
        finally
        {
            // We can rely on control always returning here afterclient.use(); it is safer than convention based mechanisms.
            // At this point we can do whatever we want or is needed.
            // Such as releasing resources and decrementing a count of Frobstinators in use.
        }
    }
}

Use:

Oelong mifftibleOelong()
{
    Oelong oelongToMifftible = new Oelong();
    FrobstinatorProvider provider = repo.giveFrobstinatorProvider();
    return provider.withFrobstinatorDo(
        new IFrobstinatorUser<Oelong> {
            Oelong use(Frobstinator item) {
                return item.mifftible(oelongToMifftible);
            }
        });
}

'Frobstinator', 'Oelong', and 'mifftible' are made-up words standing for a service, object, and action respectively.

The advantage of using a procedure (method) that calls a callback with the resource, the callback needs to use, is that control almost always returns to the stamenent after the callback; giving us the opportiunity to always do something when the resource is no longer used.

Kasper van den Berg
  • 2,636
  • 1
  • 16
  • 32
  • Probably ought to have a `try` … `finally` in there, otherwise you might end up with unreleased resources if the user code throws an exception. – Ilmari Karonen Nov 26 '19 at 10:57
  • Most often yes. However the scheme gives you complete freedom to handle resources and exceptions any way you want in `withFrobstinatorDo()`. Updated answer to clarify though; thank for the heads up. – Kasper van den Berg Nov 26 '19 at 12:16