Problem with Finalize objects in GC cycle

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • ask4rishi
    New Member
    • Aug 2007
    • 3

    Problem with Finalize objects in GC cycle

    Hi ,

    We are monitoring the applications using the verboseGC. And in our application we have large number of finalize method. We have observed through VerboaseGC logs that lots of Finalize objects has queued up on each GC cycle.
    And We know that the garbage collector needs a minimum of two cycles (maybe more GC cycles) to reclaim Finalize objects and needs to retain all other objects reachable from them during this process. But is there any other way to tune this problem irrespacting of rewrite the application code again.
    Please help me on this.

    VerboaseGC logs:

    Few sample of finalization objects queued parameter in GC logs:

    <finalization objectsqueued=" 198" />
    <finalization objectsqueued=" 3960" />
    <finalization objectsqueued=" 1102" />
    <finalization objectsqueued=" 690" />
    <finalization objectsqueued=" 63" />
    <finalization objectsqueued=" 206" />
    <finalization objectsqueued=" 75" />
    <finalization objectsqueued=" 1034" />
    <finalization objectsqueued=" 740" />
    <finalization objectsqueued=" 684" />
    <finalization objectsqueued=" 1110" />
    <finalization objectsqueued=" 762" />
    <finalization objectsqueued=" 1142" />
  • JosAH
    Recognized Expert MVP
    • Mar 2007
    • 11453

    #2
    Imagine the following artificial scenario:

    [code=java]
    public class A {
    pivate B b;
    public A(B b) { this.b= b; }
    public void setB(B b) { this.b= b; }
    public cycle(int i) { if (i > 0) b.cycle(--i); }
    protected void finalize() { cycle(42); }
    }
    public class B {
    pivate A a;
    public B(A a) { this.a= a; }
    public void setA(A a) { this.a= a; }
    public cycle(int i) { if (i > 0) a.cycle(--i); }
    protected void finalize() { cycle(42); }
    }
    ...
    B b= new b(null);
    A a= new A(b);
    b.setA(a);
    a= null;
    b= null;
    // GC hit here ...
    [/code]

    At the end of that piece of code both a and b are eligable for garbage collection.
    For one of them the finalize() method is invoked; the other one can't be collected
    yet. Depending on which finalize() method was invoked first none of the other
    objects can be collected. Even after the first finalizer is ready, the object can't
    be collected because the *other* finalizer still needs it. Finalizers are a mess ...

    kind regards,

    Jos

    Comment

    • ask4rishi
      New Member
      • Aug 2007
      • 3

      #3
      Hi Jos,

      Thank you very much for your kind suggestion. This means there is no other alternative except change the application. What do you suggest? Is there any efficient way to change the finalize method?

      Thanks and regards,
      Rishi.


      Originally posted by JosAH
      Imagine the following artificial scenario:

      [code=java]
      public class A {
      pivate B b;
      public A(B b) { this.b= b; }
      public void setB(B b) { this.b= b; }
      public cycle(int i) { if (i > 0) b.cycle(--i); }
      protected void finalize() { cycle(42); }
      }
      public class B {
      pivate A a;
      public B(A a) { this.a= a; }
      public void setA(A a) { this.a= a; }
      public cycle(int i) { if (i > 0) a.cycle(--i); }
      protected void finalize() { cycle(42); }
      }
      ...
      B b= new b(null);
      A a= new A(b);
      b.setA(a);
      a= null;
      b= null;
      // GC hit here ...
      [/code]

      At the end of that piece of code both a and b are eligable for garbage collection.
      For one of them the finalize() method is invoked; the other one can't be collected
      yet. Depending on which finalize() method was invoked first none of the other
      objects can be collected. Even after the first finalizer is ready, the object can't
      be collected because the *other* finalizer still needs it. Finalizers are a mess ...

      kind regards,

      Jos

      Comment

      • JosAH
        Recognized Expert MVP
        • Mar 2007
        • 11453

        #4
        Originally posted by ask4rishi
        Hi Jos,

        Thank you very much for your kind suggestion. This means there is no other alternative except change the application. What do you suggest? Is there any efficient way to change the finalize method?

        Thanks and regards,
        Rishi.
        I'd say don't implement finalizers; for real resources (open files, sockets etc.)
        close them as soon as you're done with them; don't delay that to the finalization
        stage. If you're done with a POJO (Plain Old Java Object) you could set its
        reference to null a.s.a.p. but don't use finalizers; as I wrote: they're a mess.

        Comment

        • sumittyagi
          Recognized Expert New Member
          • Mar 2007
          • 202

          #5
          Originally posted by JosAH
          Imagine the following artificial scenario:

          [code=java]
          public class A {
          pivate B b;
          public A(B b) { this.b= b; }
          public void setB(B b) { this.b= b; }
          public cycle(int i) { if (i > 0) b.cycle(--i); }
          protected void finalize() { cycle(42); }
          }
          public class B {
          pivate A a;
          public B(A a) { this.a= a; }
          public void setA(A a) { this.a= a; }
          public cycle(int i) { if (i > 0) a.cycle(--i); }
          protected void finalize() { cycle(42); }
          }
          ...
          B b= new b(null);
          A a= new A(b);
          b.setA(a);
          a= null;
          b= null;
          // GC hit here ...
          [/code]

          At the end of that piece of code both a and b are eligable for garbage collection.
          For one of them the finalize() method is invoked; the other one can't be collected
          yet. Depending on which finalize() method was invoked first none of the other
          objects can be collected. Even after the first finalizer is ready, the object can't
          be collected because the *other* finalizer still needs it. Finalizers are a mess ...

          kind regards,

          Jos
          That means if there is an unreferenced object graph with 10 objects, then that graph will be collected in 10 gc cycles???

          Comment

          • JosAH
            Recognized Expert MVP
            • Mar 2007
            • 11453

            #6
            Originally posted by sumittyagi
            That means if there is an unreferenced object graph with 10 objects, then that graph will be collected in 10 gc cycles???
            Nope, all those objects can be reaped in one sweep; unless there are finalizer
            methods; all objects have to be kept intact (the finalizer might reference them)
            until all finalizers are done.

            There's even a nastier situation, called "resurrecti on"; here's an example:

            [code=java]
            public class Zombie {
            private static Zombie zombieHook;
            public Zombie() { }
            public void talk() { System.out.prin tln("boo!"); }
            protected void finalize() { zombieHook= this; }
            public static void main(String[] args) {
            new Zombie(); // don't refer to it
            System.gc();
            Thread.sleep(10 000); // give GC a chance
            Zombie.zombieHo ok.talk();
            }
            }
            [/code]

            kind regards,

            Jos

            Comment

            • sumittyagi
              Recognized Expert New Member
              • Mar 2007
              • 202

              #7
              Originally posted by JosAH
              Nope, all those objects can be reaped in one sweep; unless there are finalizer
              methods; all objects have to be kept intact (the finalizer might reference them)
              until all finalizers are done.

              There's even a nastier situation, called "resurrecti on"; here's an example:

              [code=java]
              public class Zombie {
              private static Zombie zombieHook;
              public Zombie() { }
              public void talk() { System.out.prin tln("boo!"); }
              protected void finalize() { zombieHook= this; }
              public static void main(String[] args) {
              new Zombie(); // don't refer to it
              System.gc();
              Thread.sleep(10 000); // give GC a chance
              Zombie.zombieHo ok.talk();
              }
              }
              [/code]

              kind regards,

              Jos
              Thanks Jos, I got the point.

              Comment

              • sumittyagi
                Recognized Expert New Member
                • Mar 2007
                • 202

                #8
                Originally posted by sumittyagi
                Thanks Jos, I got the point.
                But one silly question was striking my mind. is't it the case all the finalize methods get called in one gc cycle of that graph??? for eg. the A and B class you gave in you example, can't gc run both the methods in one cycle. I think there won't be any inconsistency due to that. I know this question is sounding silly, but please guide me in this context.

                Comment

                • JosAH
                  Recognized Expert MVP
                  • Mar 2007
                  • 11453

                  #9
                  Originally posted by sumittyagi
                  But one silly question was striking my mind. is't it the case all the finalize methods get called in one gc cycle of that graph??? for eg. the A and B class you gave in you example, can't gc run both the methods in one cycle. I think there won't be any inconsistency due to that. I know this question is sounding silly, but please guide me in this context.
                  Sure, all finalizers can be run in separate threads if the GC decides to do so;
                  but imagine if all finalizers synchronize on one object; that little nasty scenario
                  I sketched above forces the GC to postpone the actual reaping until all finalizers
                  are finished (sequentially). Finalizers can slow down the GC considerably and
                  therefore slow down the user threads as well. As I wrote: it's better *not* to
                  implement finalizers.

                  kind regard,

                  Jos

                  Comment

                  • sumittyagi
                    Recognized Expert New Member
                    • Mar 2007
                    • 202

                    #10
                    Originally posted by JosAH
                    Sure, all finalizers can be run in separate threads if the GC decides to do so;
                    but imagine if all finalizers synchronize on one object; that little nasty scenario
                    I sketched above forces the GC to postpone the actual reaping until all finalizers
                    are finished (sequentially). Finalizers can slow down the GC considerably and
                    therefore slow down the user threads as well. As I wrote: it's better *not* to
                    implement finalizers.

                    kind regard,

                    Jos
                    Great!! got the point!

                    Comment

                    • ask4rishi
                      New Member
                      • Aug 2007
                      • 3

                      #11
                      Thank you very much for ur response.
                      With regards,
                      Rishi.

                      Comment

                      Working...