jimcoly / h2database

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

Memory if many connections are opened and closed on Android #590

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Hi,

i've found a problem when running h2 database on android.
The test Program shown below runs fine on my desktop.
Connections are created and rolled back and the memory usage is nearly constant.
But if you put the loop into the onResume() method of an android app it will
eat up memory until you get an outofmemoryerror. 
I would expect it to work like the desktop version without using all memory.
I am using h2 1.3.174 and the android emulator for version 4.1.2
But i also tried the current version 1.4.182 and android 4.4.2. same result.

import java.sql.Connection;
import java.sql.DriverManager;

import javax.swing.JFrame;

class Test
{
    public static void main(String[] args) throws Exception
    {
        new Test();
    }

    public Test() throws Exception
    {
        Class.forName("org.h2.Driver");
        long count = 0;
        Connection con2 = DriverManager.getConnection("jdbc:h2:///tmp/db", "sa", "");
        while(true)
        {
            count++;
            Connection con = null;
            try
            {                
                con = DriverManager.getConnection("jdbc:h2:///tmp/db", "sa", "");
                con.createStatement().execute("xy");
            }
            catch(Exception ex)
            {
                con.rollback();
                con.close();
            }
            if(count % 1000 == 0)
            {
                System.gc();
                System.out.println("" + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) + " / " + Runtime.getRuntime().totalMemory());
            }
        }
    }

}

- Do you know a workaround?
Do not create new connections...?

Hopefully you can find the cause of this misbehavior.

thank you for this great software
martin

Original issue reported on code.google.com by keinh...@gmail.com on 25 Oct 2014 at 5:22

GoogleCodeExporter commented 9 years ago
I tried to analyse a heap dump from android, and it seems, that there are lots 
of Session Objects hanging around. But i could not find the reason why they are 
still referenced.

Original comment by keinh...@gmail.com on 26 Oct 2014 at 9:35

GoogleCodeExporter commented 9 years ago
This is a question for the mailing list. The bugtracker is not a discussion 
forum.

Original comment by noelgrandin on 26 Oct 2014 at 1:48

GoogleCodeExporter commented 9 years ago
Why is this an discussion? Its clearly a bug, because i get an outofmemoryerror.

Original comment by keinh...@gmail.com on 26 Oct 2014 at 2:21

GoogleCodeExporter commented 9 years ago
Hi,

Well, it's not clear where the bug is, it could be in your application. I don't 
think it makes sense to log a bug if you don't know yet.

Did you read 
http://h2database.com/html/tutorial.html?highlight=Android&search=android#androi
d ? 

Original comment by thomas.t...@gmail.com on 26 Oct 2014 at 4:19

GoogleCodeExporter commented 9 years ago
Hi,

yes i've read that already.
And i made a simple example to demonstrate the bug (see code above).
Maybe it is my Android Applications fault... So i simplified my App to include 
only the example from above. Here is the complete Activity class. Its the one 
and only Activity. No UI, nothing but this:

package de.exware.ffmanager.android;
import java.io.File;
import java.sql.*;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
public class FFManager extends Activity 
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    { 
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onResume()  
    {
        super.onResume();
        try
        {
            Class.forName("org.h2.Driver");
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        } 
        File extfile = getExternalFilesDir(null);
        if(extfile == null)
        {
            extfile = Environment.getExternalStorageDirectory();
        }
        File file = new File(extfile,"database/db");
        String dburl = "jdbc:h2:" + file.getAbsolutePath() 
            + ";FILE_LOCK=FS" 
            + ";PAGE_SIZE=1024" 
            + ";CACHE_SIZE=128";
        Connection con = null;
        Statement stm = null;
        while(true)
        {
            try
            {
                con = DriverManager.getConnection(dburl, "sa", "");
                stm = con.createStatement();
                stm.execute("xy");                
            }
            catch(Exception ex)
            {
                try
                {
                    stm.close();
                    con.rollback();
                    con.close();
                }
                catch (SQLException e)
                {
                    e.printStackTrace();
                }
            }
        }
    } 
}

And here you see the growing memory from the logcat output, which is nearly 1MB 
in 10 seconds. Which is very much if there are only 16MB available.

10-26 17:49:57.837: D/dalvikvm(2211): GC_FOR_ALLOC freed 324K, 10% free 
3592K/3972K, paused 3ms, total 4ms
10-26 17:50:05.177: D/dalvikvm(2211): GC_FOR_ALLOC freed 398K, 11% free 
3701K/4152K, paused 3ms, total 4ms
10-26 17:50:05.777: D/dalvikvm(2211): GC_FOR_ALLOC freed 306K, 9% free 
3906K/4264K, paused 4ms, total 4ms
10-26 17:50:06.417: D/dalvikvm(2211): GC_FOR_ALLOC freed 392K, 10% free 
4028K/4472K, paused 4ms, total 4ms
10-26 17:50:07.017: D/dalvikvm(2211): GC_FOR_ALLOC freed 314K, 8% free 
4226K/4592K, paused 5ms, total 5ms
10-26 17:50:07.617: D/dalvikvm(2211): GC_FOR_ALLOC freed 399K, 10% free 
4342K/4792K, paused 5ms, total 5ms
10-26 17:50:08.237: D/dalvikvm(2211): GC_FOR_ALLOC freed 330K, 8% free 
4558K/4940K, paused 6ms, total 6ms

I also found, that leaving away this line:

                stm.execute("xy");

does no longer create the issue. Also replacing it with a valid select 
statement solves the issue. So i can create lots of connections which are 
garbage collected without being explicitly closed. But if i execute a single 
statement which failes, then neither rollback(), nor close() will free the 
memory.

So i still think it is a bug. 

And yes, the sample is not an real world app (just demo). I'm trying hard to 
avoid exceptions like the one produced here. This bug hit me during development 
phase, because of an bug in my real application.

thanks for your quick responses.
martin

Original comment by keinh...@gmail.com on 26 Oct 2014 at 5:27

GoogleCodeExporter commented 9 years ago
Hello,

it's me again :-)
I've searched google for a couple of hours the last 2 days and it seems like i 
have found the solution for this strange problem.

The bug is not in my APP, and also is not in h2. 

Seems like the bug is in the Android Debugger. 
As shown above the memory usage is growing rapidly, but, to my surprise, only 
if the Debugger is connected (which i did all the time, because i'm 
developing). 
If the APP is launched without debugger, everything works. No more memory 
leaking. 
If the APP is started in debugging mode and the debugger is disconnected after 
some time, the leaking stops and the leaked memory will be freed. 
If the debugger is connected to an already running APP, memory leaking starts 
again until the debugger is disconnected again.

Maybe you could put a note about this behavior on your Tutorial page, so other 
guys won't run in the wrong direction like me.
http://h2database.com/html/tutorial.html?highlight=Android&search=android#androi
d

thank you for your patience
martin

Original comment by keinh...@gmail.com on 29 Oct 2014 at 5:51