噩梦java泄漏...与循环和jdbc [英] Nightmare java leak... with loop and jdbc

查看:112
本文介绍了噩梦java泄漏...与循环和jdbc的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在事件探查器中运行以下代码时,我会得到一个char []和byte [],直到由于Java堆内存不足异常而使程序崩溃为止.有人可以告诉我为什么吗?也许我在做一些根本错误的事情.

When I run the following code in the profiler, I get a char[] and byte[] that build up until the program crashes due to a java heap out of memory exception. Can someone tell me why? Perhaps I am doing something fundamentally wrong.

package testleak;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.swing.Timer;

    public class TestLeak
    {
        static String DB_USERNAME = "userName";
        static String DB_SUBSCRIPTION_EXPIRATION = "subscriptionExpiration";
        static String DB_REMOTE_ACCESS_ENABLED = "remoteAccessEnabled";
        static String DB_LOCAL_USERNAME = "root";
        static String DB_LOCAL_PASS = "root";
        public static void main(String[] args)
        {
            Timer timer = new Timer(2000, new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent evt)
                {
                    TestLeak tester = new TestLeak();
                    try
                    {
                       tester.go();
                    }
                    catch (NumberFormatException n)
                    {
                    }
                    tester = null;
                }
            });
            timer.start();
            while (true)
            {
                //keep the program from ending...
            }

        }
        private void go() throws NumberFormatException
        {
            ResultSet results = null;
            Connection conn = null;
            Properties connectionProps = new Properties();
            try
            {
                connectionProps.put("user", "root");
                connectionProps.put("password", "root");
                conn = DriverManager.getConnection("jdbc:mysql://localhost:8889/myDataBase",
                        connectionProps);
                connectionProps = null;
                try
                {
                    String rawQuery = new String("SELECT " + TestLeak.DB_USERNAME + ", "
                            + TestLeak.DB_REMOTE_ACCESS_ENABLED
                            + ", " + TestLeak.DB_SUBSCRIPTION_EXPIRATION + " FROM myTable");
                    Statement statement = conn.createStatement();
                    try
                    {
                        statement.executeQuery(rawQuery);
                        results = statement.getResultSet();
                        rawQuery = null;
                        try
                        {
                            while (results.next())
                            {
                                String auth = new String(results.getString(TestLeak.DB_REMOTE_ACCESS_ENABLED));
                                if (auth.equals("1"))
                                {
                                    Long subExpires = Long.valueOf(results.getString(TestLeak.DB_SUBSCRIPTION_EXPIRATION));
                                    if (subExpires > System.currentTimeMillis())
                                    {
                                        System.out.println(results.getString(TestLeak.DB_USERNAME));
                                        System.out.println();
                                    }
                                    subExpires = null;
                                }
                                auth = null;
                            }
                        }
                        finally
                        {
                            results.close();
                        }
                    }
                    finally
                    {
                        statement.close();
                    }
                }
                finally
                {
                    conn.close();
                }
            }
            catch (SQLException e)
            {
                System.out.println(e.getMessage());
            }
        }
    }

我认为我正在释放所有内容,但是必须采取某种措施来阻止所有对象被释放.当go()方法结束时,为什么所有对象都不符合垃圾回收的条件?每次我在分析器中调用垃圾收集时,我都会得到另一个幸存的一代. 谢谢.

I think I am releasing everything, but something must be preventing all objects from being released. Why is it that all objects are not eligible for garbage collection when the go() method ends? Every time I envoke garbage collection in the profiler I get another surviving generation. Thanks.

推荐答案

不幸的是,您没有指定有关该问题的一些详细信息,例如,结果集有多大(行数)以及需要多长时间?遇到内存不足异常.

Unfortunately you don't specify some details about the problem, for example, how big is the result set (# of rows), and how long does it take to run into out of memory exception.

我现在无法访问您拥有的mysql驱动程序,但是我在H2数据库中运行了相同的代码,在myTable中有1000行.在测试期间,JVM的堆大小是稳定的,没有任何内存泄漏.您可以在所附的屏幕截图中看到它. 堆大小略有增加,然后在GC之后以非常稳定的模式返回到原来的位置,又一次又一次地下降.

I don't have access right now to the mysql driver you have, but I ran your same code with an H2 database, with 1000 rows in the myTable. The heap size of the JVM was stable during the test, without any memory leak. You can see that in the attached screenshot. The heap size increased a little, then returned to the original position after the GC, up again, down again, on a very stable pattern.

您可以运行您的应用程序,然后运行Jvisualvm并连接到您的应用程序,以查看例如来自数据库的结果数量是否太大而无法容纳到现有内存中.这是我的猜测.在这种情况下,蓝线将迅速超过最大内存.

You can run your app and then run the Jvisualvm and connect to your app to see, for example, if the number of results from the database is too large to fit into the existing memory. Which is my guess. In this case the blue line will rapidly go over the max memory.

在这种情况下,请使用-Xmx设置运行应用程序以增加内存大小.

If that's the case you run your application with -Xmx setting to increase the memory size.

如果确实存在内存泄漏,则它不在您的代码中,而是在您使用的驱动程序中.为了确认内存泄漏,下表中的蓝线会上升(分配内存),GC将运行(释放内存),但蓝线永远不会回到其原始位置并留下一些对象.

If indeed there is a memory leak it is not in your code, but in the driver you're using. To confirm a memory leak, the blue line in the chart below will go up (allocating memory), the GC will run (freeing up memory) but the blue line never gets back to it's original position leaving behind some objects.

这篇关于噩梦java泄漏...与循环和jdbc的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆