Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4483833

ORB memory leak when invoking inactive IOR

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 1.4.0
    • 1.4.0
    • other-libs
    • beta3
    • sparc
    • solaris_8
    • Not verified



        Name: krC82822 Date: 07/24/2001


        (508) ~/working/CORBALeakTest $ java -version
        java version "1.4.0-beta_refresh"
        Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta_refresh-b70)
        Java HotSpot(TM) Client VM (build 1.4.0-beta_refresh-b70, mixed mode)
        (509) ~/working/CORBALeakTest $ uname -a
        SunOS rental5 5.8 Generic_108528-05 sun4u sparc SUNW,Ultra-80

        Java ORB operations on inactive object references leak memory, where 'inactive'
        is defined as 'derived from a valid CORBA IOR, but no servant object currently
        exists'; that is, ref._non_existent() will return true for an inactive
        reference.

        The following code will demonstrate the problem (4 files):

        ----- cut here -----

        // Test.idl

        module CORBALeakTest {
                interface Test {
                        void test();
                };
        };

        ----- cut here -----

        // Server.java

        package CORBALeakTest;

        import org.omg.CORBA.*;

        public class Server extends _TestImplBase {

                private static ORB orb;

                public Server() {
                        System.out.println(orb.object_to_string(this));
                }

                public void test() { }

                public static void main(String[] argv) {
                        orb = ORB.init(argv, null);
                        Server testServer = new Server();
                        synchronized (testServer) {
                                try {
                                        testServer.wait();
                                }
                                catch (InterruptedException ie) { }
                        }
                }
        }

        ----- cut here -----

        // Client1.java

        package CORBALeakTest;

        import org.omg.CORBA.*;

        public class Client1 {

                private static ORB orb;

                public Client1(String ior) {
                        Test testServer = TestHelper.narrow(orb.string_to_object(ior));
                        long i = 0;
                        while (true) {
                                try {
                                        testServer.test();
                                }
                                catch (Throwable t) { }
                                i++;
                                if (i % 1000 == 0) {
                                        System.out.println(i);
                                }
                        }
                }

                public static void main(String[] argv) {
                        orb = ORB.init(argv, null);
                        Client1 testClient = new Client1(argv[0]);
                }
        }

        ----- cut here -----

        // Client2.java

        package CORBALeakTest;

        import org.omg.CORBA.*;

        public class Client2 {

                private static ORB orb;

                public Client2(String ior) {
                        Test testServer = TestHelper.narrow(orb.string_to_object(ior));
                        long i = 0;
                        while (true) {
                                if (!testServer._non_existent()) {
                                        try {
                                                testServer.test();
                                        }
                                        catch (Throwable t) { }
                                        i++;
                                        if (i % 1000 == 0) {
                                                System.out.println(i);
                                        }
                                }
                        }
                }

                public static void main(String[] argv) {
                        orb = ORB.init(argv, null);
                        Client2 testClient = new Client2(argv[0]);
                }
        }

        ----- cut here -----

        Compile the test program:
        sh-2.03$ idlj -fall Test.idl
        sh-2.03$ javac CORBALeakTest/*.java
        sh-2.03$ javac -d . *.java

        Run the server program:
        bash-2.03$ java -cp . CORBALeakTest.Server
        IOR:000000000000001b49444c3a434f5242414c65616b546573742f546573743a312e3000000000
        00010000000000000050000101000000000931302e312e332e350000c19200000018afabcaff0000
        00021f84eefe00000008000000000000000000000001000000010000001400000000000100200000
        00000001010000000000

        Now run either client program in another window, pasting in the IOR from the
        server:
        bash-2.03$ java -verbose:gc -cp . CORBALeakTest.Client1
        IOR:000000000000001b49444c3a434f5242414c65616b546573742f546573743a312e3000000000
        00010000000000000050000101000000000931302e312e332e350000c19200000018afabcaff0000
        00021f84eefe00000008000000000000000000000001000000010000001400000000000100200000
        00000001010000000000

        The client will behave as expected while the server is alive:
        [GC 2047K->265K(3520K), 0.0177870 secs]
        [GC 2313K->269K(3520K), 0.0034574 secs]
        [GC 2317K->269K(3520K), 0.0005427 secs]
        1000
        [GC 2316K->269K(3520K), 0.0007788 secs]
        [GC 2317K->269K(3520K), 0.0006590 secs]
        2000
        [GC 2317K->266K(3520K), 0.0005505 secs]
        [GC 2314K->267K(3520K), 0.0005440 secs]
        [GC 2315K->269K(3520K), 0.0007811 secs]
        3000
        [GC 2316K->269K(3520K), 0.0006570 secs]
        [GC 2317K->269K(3520K), 0.0005915 secs]
        [GC 2317K->269K(3520K), 0.0005910 secs]
        4000
        [GC 2316K->269K(3520K), 0.0006335 secs]
        [GC 2317K->270K(3520K), 0.0006795 secs]
        5000
        [GC 2318K->267K(3520K), 0.0005561 secs]
        [GC 2315K->269K(3520K), 0.0006200 secs]
        [GC 2317K->269K(3520K), 0.0006153 secs]
        6000
        [GC 2316K->269K(3520K), 0.0005899 secs]
        [GC 2317K->269K(3520K), 0.0006921 secs]
        [GC 2316K->269K(3520K), 0.0006568 secs]
        7000
        [GC 2317K->270K(3520K), 0.0006323 secs]
        [GC 2317K->267K(3520K), 0.0005877 secs]
        [GC 2315K->269K(3520K), 0.0007086 secs]
        8000
        [GC 2316K->269K(3520K), 0.0007561 secs]
        [GC 2317K->269K(3520K), 0.0006853 secs]
        9000
        [GC 2316K->269K(3520K), 0.0005801 secs]
        [GC 2317K->269K(3520K), 0.0006956 secs]
        [GC 2316K->269K(3520K), 0.0006479 secs]
        10000
        ... and so on, for as long as you like.

        However, if the server is then killed, the client output will change:
        10000
        [GC 2317K->270K(3520K), 0.0005439 secs]
        [GC 2317K->267K(3520K), 0.0005547 secs]
        [GC 2315K->269K(3520K), 0.0005765 secs]
        11000
        [GC 2316K->269K(3520K), 0.0005803 secs]
        [GC 2317K->269K(3520K), 0.0005904 secs]
        12000
        [GC 2316K->269K(3520K), 0.0005895 secs]
        [GC 2317K->269K(3520K), 0.0007001 secs]
        [GC 2316K->269K(3520K), 0.0005749 secs]
        13000
        [GC 2317K->266K(3520K), 0.0004868 secs]
        [GC 2314K->436K(3520K), 0.0071911 secs]
        [GC 2483K->609K(3520K), 0.0097806 secs]
        [GC 2657K->780K(3520K), 0.0089063 secs]
        14000
        [GC 2828K->950K(3520K), 0.0092645 secs]
        [GC 2997K->1120K(3520K), 0.0085689 secs]
        [GC 3167K->1282K(3520K), 0.0087205 secs]
        15000
        [GC 3330K->1453K(3520K), 0.0093006 secs]
        [GC 3501K->1636K(3776K), 0.0098931 secs]
        [Full GC 3684K->1648K(4864K), 0.0989441 secs]
        [GC 3695K->1819K(4864K), 0.0086588 secs]
        16000
        [GC 3867K->1988K(4864K), 0.0090824 secs]
        [GC 4036K->2159K(4864K), 0.0093072 secs]
        [GC 4206K->2330K(4864K), 0.0093556 secs]
        17000
        [GC 4378K->2500K(4864K), 0.0087803 secs]
        [GC 4548K->2698K(4864K), 0.0102028 secs]
        [GC 4745K->2868K(4992K), 0.0091434 secs]
        [Full GC 4916K->2844K(6856K), 0.1272475 secs]
        18000
        [GC 4892K->3014K(6856K), 0.0084714 secs]
        [GC 5062K->3184K(6856K), 0.0093803 secs]
        [GC 5232K->3356K(6856K), 0.0093356 secs]
        19000
        ...and so on until the JVM runs out of heap space and dies.

        Note that the full GCs are not able to reclaim all of the allocated memory.
        The client program isn't creating any objects itself, so this memory must be
        getting lost in the ORB classes somewhere. The same effect is seen with both
        clients, so it appears that even explicitly checking for a valid IOR with
        _non_existent() won't save you, since this method causes a memory leak as well!

        With the JDK-1.4.0-beta, I see the same behaviour [as in 1.3.1],
        under both Solaris and Windows.

        You might argue that invoking operations on an IOR that isn't backed by a
        servant object is just a stupid thing to do, but this is certainly something
        that *will* happen when servant objects go away unexpectedly -- catching an
        exception from an operation is often how you find out that the servant is no
        longer around. It is only a small amount of memory that is leaked each time,
        but in a long-lived application, monitoring a large number of remote peers,
        this will add up to a serious leak over time.
        (Review ID: 128510)
        ======================================================================


              hputtaswsunw Hemanth Puttaswamy (Inactive)
              kryansunw Kevin Ryan (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: