Support for library unloading

Issue #61 wontfix
Former user created an issue

Originally reported on Google Code with ID 61

Need support to unload the class/library that gets loaded in main() in SQLite.java

When running this in a servlet, and web app needs to reload, an error is thrown and
tomcat is crashing:

Caused by: java.lang.UnsatisfiedLinkError: Native Library sqlite4java-win32-x64.dll
already loaded in another classloader

Reported by synologic on 2014-05-19 05:20:48

Comments (6)

  1. Former user Account Deleted
    Unloading should have happened when the classloader was garbage collected. It doesn't
    seem to be any other way. Check if your servlet hangs on in memory and prevents the
    classloader from be gc-ed. See also: http://stackoverflow.com/questions/453359/how-to-unload-dll-from-java-jvm
    
    If you have a specific request of how exactly can we improve sqlite4java to support
    servlet unloading, please suggest.
    

    Reported by sereda@almworks.com on 2014-05-19 06:55:17 - Status changed: WontFix - Labels added: Type-Enhancement - Labels removed: Type-Defect

  2. Former user Account Deleted
    Since i'm no expert in JNI, i can't provide a solution to this, however i think that
    the class loader does not get GC-ed for some other reason.
    
    Consider the following context listener:
    
    @WebListener
    public class AppContext implements ServletContextListener {
    
        public AppContext() {
        }
    
        public void contextDestroyed(ServletContextEvent arg0) {
            // TODO Auto-generated method stub
        }
    
        public void contextInitialized(ServletContextEvent arg0) {
            SQLiteConnection dataBase;
            String filePath = "c://temp//test.db";
            dataBase = new SQLiteConnection(new File(filePath));
            try {
                dataBase.open();
            } catch (SQLiteException e) {
                e.printStackTrace();
            }
            dataBase.dispose();
            dataBase = null;
            System.gc();
            System.out.println("Context initialized !");
        }
    }
    
    This is a simple test.
    Even after manually performing GC, the error persists on reload of the web application,
    which leads me to believe that a reference to the class loader still exists somewhere.
    

    Reported by synologic on 2014-05-19 07:23:04

  3. Former user Account Deleted
    The reference indeed exists when you perform System.gc() because this class is still
    being used. Can you try moving System.gc() to the beginning of the method, so it collects
    the previously freed classloaders?
    
    Another option would be to change the context classloader to the system classloader,
    and do a manual sqlite initialization with SQLite.loadLibrary().
    

    Reported by sereda@almworks.com on 2014-05-19 07:27:52

  4. Former user Account Deleted
    That worked, it may be a good idea to have that put in main() in SQLite.java in the
    next release to alleviate this problem.
    

    Reported by synologic on 2014-05-19 07:32:06

  5. Former user Account Deleted
    Can you please clarify, which thing did work? I'm not sure about putting any of these
    approaches into the library itself as it could be harmful in certain cases. Also, System.gc()
    is not guaranteed to do anything at all, so production code should not rely on it.
    

    Reported by sereda@almworks.com on 2014-05-19 13:28:24

  6. Former user Account Deleted
    Well the simple test i posted above worked with System.gc() as first line in contextInitialized,
    however after doing the same thing in my main application, had no effect.
    
    I guess i would have to refrain from reloading my webapp and restart tomcat whenever
    changes occur.
    

    Reported by synologic on 2014-05-19 13:54:42

  7. Log in to comment