【问题标题】:simple java loop writing to database causes out of memory exception简单的java循环写入数据库导致内存不足异常
【发布时间】:2014-02-28 22:15:58
【问题描述】:

我有以下循环运行的守护进程:

public class MyDaemon implements Daemon {

    private Thread myThread;
    private boolean stopped = false;

    private DatagramChannel channel;

    @Override
    public void init(DaemonContext daemonContext) throws DaemonInitException,
            Exception {

        myThread = new Thread() {

            @Override
            public synchronized void start() {
                MyDaemon.this.stopped = false;
                super.start();
            }

            @Override
            public void run() {
                            ByteBuffer buf = ByteBuffer.allocate(100);

                while (!stopped) {

                    try {
                        channel.receive(buf);
                        String payload = buf;
                        ArrayList<Element> elements = buf.elements();

                        Message message = new Message();
                        message.setPayload();
                        message.setElements(elements);

                        DataManager controller = null;
                        try {
                            dm = new DataManager();
                        } catch (ClassNotFoundException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (SQLException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        dm.saveMessage(message);
                        Thread.sleep(100);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }
            }
        };
    }

    public static void main(String args[]) {

    }

    @Override
    public void start() throws Exception {

        channel = DatagramChannel.open();
        channel.socket().bind(new InetSocketAddress(1400));
        channel.configureBlocking(false);
        myThread.start();
    }

    @Override
    public void stop() throws Exception {

        stopped = true;
        try {
            myThread.join(1000);
        } catch (InterruptedException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }

    @Override
    public void destroy() {
        myThread = null;
    }
}

我的数据管理器类如下所示:

public class DataManager {

    private static String insert = "insert into mytable "
                        + “(payload, elementId, time)”
                        + "values (?,?,?);”;

    public Connection instantiateConnection() throws ClassNotFoundException,
            SQLException {



        Connection connection = DriverManager.getConnection("jdbc connection info”);

        return connection;
    }



    public void saveMessage(Message message) {
        try {
            Connection connection = this.instantiateConnection();

                connection.setAutoCommit(false);
                PreparedStatement ps = connection.prepareStatement(insert);

                for (Element element : message.getElements()) {
                    Timestamp time = new Timestamp(date.getTime());
                    ps.setString(1, message.getPayload());
                    ps.setString(2, element.getId());
                           ps.setTimestamp(3, time);
                    ps.addBatch();
                }
                ps.executeBatch();
                connection.commit();
                ps.close();
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

}

最后,这是运行我的守护进程的 ssh 文件:

#!/bin/sh

# Setup variables EXEC=/usr/bin/jsvc



PID=/tmp/mydaemon.pid JAVA_HOME=/usr/lib/jvm/jre CLASS_PATH="/home/ec2-user/commons-daemon-1.0.15.jar”:”/MyDaemon.jar" CLASS=MyDaemon USER=ec2-user LOG_OUT=/tmp/mydaemon.out LOG_ERR=/mydaemon.err

do_exec() {
    $EXEC -home "$JAVA_HOME" -cp $CLASS_PATH -user $USER -outfile $LOG_OUT -errfile $LOG_ERR -pidfile $PID $1 $CLASS }

case "$1" in
    start)
        do_exec
            ;;
    stop)
        do_exec "-stop"
            ;;
    restart)
        if [ -f "$PID" ]; then
            do_exec "-stop"
            do_exec
        else
            echo "service not running, will do nothing"
            exit 1
        fi
            ;;
    *)
            echo "usage: daemon {start|stop|restart}" >&2
            exit 3
            ;; esac

这是一套完整的代码。请帮忙!

运行时,内存会缓慢增长,直到出现内存不足异常。

有谁知道泄露了什么?

【问题讨论】:

  • 我会运行 jdb 来解决内存泄漏问题,这是解决所有 java 调试器问题的最简单方法
  • 我认为 DriverManager 实例会创建 OutOfMemoryError,(它会创建很多 Connection 对象)尝试使用连接池。

标签: java loops jakarta-ee memory-leaks daemon


【解决方案1】:

您在 while 循环的每次迭代中分配缓冲区。这是多余的,您不需要它,因为您在循环结束时清除缓冲区。这样做:

  ByteBuffer buf = ByteBuffer.allocate(100); 
  while(!stopped)
  {
     // do something

      buf.clear();
 }

【讨论】:

  • 那行不通。记忆还在增长。不过我很有希望。
  • 另外你为什么每次都在循环中创建一个新的 DataManager 实例..尝试使方法 save() 静态
  • @Atma 在获得异常之前循环完成了多少次迭代
  • 我在循环中这样做是因为我认为如果它存在在那里它会垃圾收集?
  • 尝试分析您的代码以查看代码的哪一部分占用了最大内存。也许有些对象永远不会被取消引用,因此对垃圾收集器不可见
【解决方案2】:

@Rembo 谢谢一百万!你是对的。

我添加了 c3p0 连接池,从那以后我一直像 1 月的流浪汉一样收集垃圾。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-15
    • 2011-05-26
    • 2013-06-22
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多