AmilyWang / sqlite4java

Automatically exported from code.google.com/p/sqlite4java
0 stars 0 forks source link

Support for library unloading #61

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
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

Original issue reported on code.google.com by synolo...@gmail.com on 19 May 2014 at 5:20

GoogleCodeExporter commented 8 years ago
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.

Original comment by ser...@almworks.com on 19 May 2014 at 6:55

GoogleCodeExporter commented 8 years ago
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.

Original comment by synolo...@gmail.com on 19 May 2014 at 7:23

GoogleCodeExporter commented 8 years ago
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().

Original comment by ser...@almworks.com on 19 May 2014 at 7:27

GoogleCodeExporter commented 8 years ago
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.

Original comment by synolo...@gmail.com on 19 May 2014 at 7:32

GoogleCodeExporter commented 8 years ago
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.

Original comment by ser...@almworks.com on 19 May 2014 at 1:28

GoogleCodeExporter commented 8 years ago
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.

Original comment by synolo...@gmail.com on 19 May 2014 at 1:54