为什么我的Java应用程序(没有内存泄漏)随着时间的推移变慢

时间:2014-10-16 13:05:35

标签: java performance memory-leaks garbage-collection

所以基本上我有一个java应用程序,加速越来越慢(即使我重置了我的JVM)。也没有检测到内存泄漏。操作VM选项到(-Xmx1024m)后,GC工作正常。

无论如何,我试图做的是运行一个带有一些代码的for循环超过40,000次但是它变得越来越慢。

循环是这样的(我必须删除版权问题的SQL查询):

for (int ab = m;ab<=(duration);ab+=600){
    jLabel_current.setText(String.valueOf(ab/600));
    System.out.println(String.valueOf(ab/600));
    System.out.println(String.valueOf(loop));

    try{
        con = datasource.getConnection();   
        for (int i=1;i<=4;i++){

            String sql=" Some query ";
            stmt = con.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                    java.sql.ResultSet.CONCUR_READ_ONLY);
            stmt.setFetchSize(Integer.MIN_VALUE);
            System.out.println(sql);
            stmt = con.createStatement();
            rs=stmt.executeQuery(sql);

            while(rs.next()){
                int a =rs.getInt("columnName");

                sql="Some query";          
                pst1=con.prepareStatement(sql);
                rs1=pst1.executeQuery();
                if(rs1.next()){                                      
                    x=rs1.getInt("columnName");
                    for(int b=0;b<x;b++){
                        if (loop!=max){
                            int task_id=parseWithDefault((jTable_task_main.getModel().getValueAt(loop, 1).toString()),0);
                            int jobb_id=parseWithDefault((jTable_task_main.getModel().getValueAt(loop, 4).toString()),0);
                            int idk=Integer.parseInt(String.valueOf(curTimeinner));
                            sql="insert into ";
                            pst2=con.prepareStatement(sql);
                            pst2.setInt(1, a);
                            pst2.setInt(2, rs1.getInt("columnName"));
                            pst2.setInt(3, rs1.getInt("columnName"));
                            pst2.setInt(4, rs1.getInt("columnName"));
                            pst2.setInt(5, rs1.getInt("columnName"));
                            pst2.setDouble(6, rs1.getDouble("columnName"));
                            pst2.setDouble(7, rs1.getDouble("columnName"));
                            pst2.setInt(8, rs1.getInt("columnName"));
                            pst2.setInt(9, rs1.getInt("columnName"));
                            pst2.setInt(10,n);
                            pst2.setInt(11,m); 
                            pst2.setInt(12, g);

                            if(rs1.getLong("columnName")<=curTime){
                                currDuration=endTask-curTimeinner;
                                pst2.setLong(13, endTask);
                                pst2.setLong(14,currDuration );

                                if(rs.getLong("columnName")>endTask){
                                    currTaskOut="successful";
                                    pst2.setString(15, currTaskOut);
                                    pst2.setInt(16, loop);
                                }else{
                                    currTaskOut="unsuccessful";
                                    pst2.setString(15, currTaskOut);
                                    pst2.setInt(16, loop);
                                }

                            }else {
                                endTask2=rs1.getLong("columnName")+120;
                                pst2.setLong(13, endTask2);
                                pst2.setLong(14, currDuration);

                                if(rs.getLong("columnName")>endTask2){
                                    currTaskOut="successful";
                                    pst2.setString(15, currTaskOut);
                                    pst2.setInt(16, loop);
                                }else{
                                    currTaskOut="unsuccessful";
                                    pst2.setString(15, currTaskOut);
                                    pst2.setInt(16, loop);
                                }                                            
                            }

                            pst2.execute();

                            loop+=1;

                            if(loop%4==0){
                                curTimeinner+=600;

                                String outcome=null;
                                String out1 = null;
                                String out2 = null;
                                String out3 = null;
                                String out4 = null;
                                ResultSet rs3=null;
                                for (int bv = 1; bv <= 4; bv++) {
                                    outcome = "unsuccessful";
                                    String sql1 = "select statment";
                                    pst1 = con.prepareStatement(sql);
                                    rs3 = pst1.executeQuery(sql1);
                                    while (rs3.next()) {
                                        if ("successful".equals(rs3.getString("task_outcome"))) {
                                            outcome = "successful";
                                        }
                                    }
                                    if (bv == 1) {
                                        out1 = outcome;
                                    } else if (bv == 2) {
                                        out2 = outcome;
                                    } else if (bv == 3) {
                                        out3 = outcome;
                                    } else {
                                        out4 = outcome;

                                        sql = "SELECT AUTO_INCREMENT";
                                        pst1 = con.prepareStatement(sql);
                                        rs3 = pst1.executeQuery(sql);
                                        if (rs3.next()) {
                                            res_id = rs3.getInt("AUTO_INCREMENT");
                                        }

                                        if ("successful".equals(out1) && "successful".equals(out2) && "successful".equals(out3) && "successful".equals(out4)) {
                                            sql = "update statment";
                                            pst1 = con.prepareStatement(sql);
                                            pst1.execute();
                                        } else {
                                            sql = "update statment";
                                            pst1 = con.prepareStatement(sql);
                                            pst1.execute();                                                                          
                                        }
                                    }
                                }
                            }
                        }
                    }
                    sql="update statment";
                    pst=con.prepareStatement(sql);
                    pst.execute(); 
                }
            }
        }
        curTime += 600;
        endTask += 600;
        ab+=600;
        max+=4;

        String sql="update statment";
        pst=con.prepareStatement(sql);
        pst.execute(); 
        ab-=600;
    }                                   

    catch (SQLException e ) {
        JOptionPane.showMessageDialog(null, e);
    } finally {
        try { if (rs != null) rs.close(); } catch(Exception e) { }
        try { if (stmt != null) stmt.close(); } catch(Exception e) { }
        try { if (con != null) con.close(); } catch(Exception e) { }
        try { if (pst != null) pst.close(); } catch(Exception e) { }
        try { if (rs1 != null) rs1.close(); } catch(Exception e) { }
        try { if (pst1 != null) pst1.close(); } catch(Exception e) { }
        try { if (rs2 != null) rs2.close(); } catch(Exception e) { }
        try { if (pst2 != null) pst2.close(); } catch(Exception e) { }
    }  
}

这是堆转储:

Java2D Disposer" daemon prio=10 tid=10 WAITING
at java.lang.Object.wait(Native Method)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:142)
   Local Variable: java.lang.ref.ReferenceQueue#72
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:158)
at sun.java2d.Disposer.run(Disposer.java:148)
   Local Variable: sun.java2d.Disposer#1
at java.lang.Thread.run(Thread.java:745)


"SwingWorker-pool-1-thread-1" daemon prio=5 tid=21 WAITING
at java.lang.Object.wait(Native Method)
at java.lang.Thread.join(Thread.java:1245)
at java.lang.Thread.join(Thread.java:1319)
at simulator.Main_panel$simulation1.doInBackground(Main_panel.java:896)
at simulator.Main_panel$simulation1.doInBackground(Main_panel.java:876)
at javax.swing.SwingWorker$1.call(SwingWorker.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
   Local Variable: javax.swing.SwingWorker$2#1
   Local Variable: javax.swing.SwingWorker$1#1
at javax.swing.SwingWorker.run(SwingWorker.java:334)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
   Local Variable: java.util.concurrent.ThreadPoolExecutor#1
   Local Variable: simulator.Main_panel$simulation1#1
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
   Local Variable: java.util.concurrent.ThreadPoolExecutor$Worker#1
at java.lang.Thread.run(Thread.java:745)


"*** Profiler Agent Special Execution Thread 6" daemon prio=5 tid=26 WAITING
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at      org.netbeans.lib.profiler.server.ProfilerServer$SeparateCmdExecutionThread.run(ProfilerServer.java:289)


"*** JFluid Monitor thread ***" daemon prio=10 tid=25 TIMED_WAITING
at java.lang.Thread.sleep(Native Method)
at org.netbeans.lib.profiler.server.Monitors$SurvGenAndThreadsMonitor.run(Monitors.java:186)


"Signal Dispatcher" daemon prio=9 tid=4 RUNNABLE


"TimerQueue" daemon prio=5 tid=20 TIMED_WAITING
at sun.misc.Unsafe.park(Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at    java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
   Local Variable: java.util.concurrent.locks.AbstractQueuedSynchronizer$Node#8
   Local Variable: java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject#3
at java.util.concurrent.DelayQueue.take(DelayQueue.java:223)
   Local Variable: java.util.concurrent.locks.ReentrantLock#77
   Local Variable: java.util.concurrent.DelayQueue#1
at javax.swing.TimerQueue.run(TimerQueue.java:171)
   Local Variable: javax.swing.TimerQueue#1
at java.lang.Thread.run(Thread.java:745)


"Attach Listener" daemon prio=5 tid=5 RUNNABLE


"Reference Handler" daemon prio=10 tid=2 WAITING
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:157)


"Thread-1" prio=5 tid=14 RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:150)
   Local Variable: java.net.SocketInputStream#1
   Local Variable: java.io.FileDescriptor#8
   Local Variable: byte[]#472
at java.net.SocketInputStream.read(SocketInputStream.java:121)
at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:114)
at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:161)
at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:189)
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2549)
   Local Variable: com.mysql.jdbc.util.ReadAheadInputStream#1
   Local Variable: byte[]#464
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3002)
   Local Variable: com.mysql.jdbc.Buffer#2
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2991)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3532)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2002)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2163)
   Local Variable: com.mysql.jdbc.MysqlIO#1
   Local Variable: java.lang.String#287058
   Local Variable: com.mysql.jdbc.Buffer#1
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2618)
   Local Variable: java.lang.String#286257
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2568)
at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1557)
   Local Variable: com.mysql.jdbc.StatementImpl#2
   Local Variable: com.mysql.jdbc.JDBC4Connection#1
at org.apache.commons.dbcp2.DelegatingStatement.executeQuery(DelegatingStatement.java:207)
   Local Variable: org.apache.commons.dbcp2.DelegatingStatement#3
at org.apache.commons.dbcp2.DelegatingStatement.executeQuery(DelegatingStatement.java:207)
   Local Variable: org.apache.commons.dbcp2.DelegatingStatement#4
at simulator.Main_panel$2.run(Main_panel.java:1011)
   Local Variable: java.lang.String#346303
   Local Variable: java.lang.String#751527


"AWT-Shutdown" prio=5 tid=11 WAITING
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at sun.awt.AWTAutoShutdown.run(AWTAutoShutdown.java:295)
   Local Variable: sun.awt.AWTAutoShutdown#1
at java.lang.Thread.run(Thread.java:745)


"Finalizer" daemon prio=8 tid=3 WAITING
at java.lang.Object.wait(Native Method)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:142)
   Local Variable: java.lang.ref.ReferenceQueue#82
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:158)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
   Local Variable: java.lang.System$2#1


"AWT-Windows" daemon prio=6 tid=12 RUNNABLE
at sun.awt.windows.WToolkit.eventLoop(Native Method)
at sun.awt.windows.WToolkit.run(WToolkit.java:303)
   Local Variable: sun.awt.windows.WToolkit#1
at java.lang.Thread.run(Thread.java:745)


"DestroyJavaVM" prio=5 tid=19 RUNNABLE


"AWT-EventQueue-0" prio=6 tid=16 WAITING
at sun.misc.Unsafe.park(Native Method)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
   Local Variable: java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject#2
   Local Variable: java.util.concurrent.locks.AbstractQueuedSynchronizer$Node#4
at java.awt.EventQueue.getNextEvent(EventQueue.java:542)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:170)
   Local Variable: java.awt.EventQueue#1
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
   Local Variable: java.awt.EventDispatchThread$HierarchyEventFilter#1
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
   Local Variable: java.awt.EventDispatchThread$1#1
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)


"*** Profiler Agent Communication Thread" daemon prio=10 tid=24 RUNNABLE
at sun.management.HotSpotDiagnostic.dumpHeap0(Native Method)
at sun.management.HotSpotDiagnostic.dumpHeap(HotSpotDiagnostic.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
   Local Variable: sun.management.HotSpotDiagnostic#2
   Local Variable: sun.reflect.NativeMethodAccessorImpl#10
   Local Variable: java.lang.Object[]#262773
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.netbeans.lib.profiler.server.system.HeapDump.takeHeapDump16(HeapDump.java:165)
   Local Variable: java.lang.String#751526
at org.netbeans.lib.profiler.server.system.HeapDump.takeHeapDump(HeapDump.java:92)
at org.netbeans.lib.profiler.server.ProfilerServer.handleClientCommand(ProfilerServer.java:1657)
at org.netbeans.lib.profiler.server.ProfilerServer.listenToClient(ProfilerServer.java:1733)
   Local Variable: org.netbeans.lib.profiler.wireprotocol.TakeHeapDumpCommand#1
at org.netbeans.lib.profiler.server.ProfilerServer.run(ProfilerServer.java:690)

1 个答案:

答案 0 :(得分:0)

它充满了资源泄漏,主要是因为将变量重用于另一个对象实例,因此没有关闭先前的实例。

  • 将变量声明为接近其首次使用并使用 try-with-resources

    String sql1 = "..."
    try (PreparedStatement pst1 = con.prepareStatement(sql1)) {
    
        for (int a = 0; a < 100; ++a) {
            pst1.setInt(1, a);
            try (ResultSet rs1 = pst1.executeQuery()) {
                while (rs1.next()) {
                }
            } // Safe close of rs1
        }
    
    } // Safe close of pst1
    
  • 为了接收生成的主键,AUTO_INCR列,java设计了一个独立于供应商的机制:

    String sql1 = "INSERT INTO table(col2, col3) VALUES(?, ?)";
    try (PreparedStatement pst1 = con.prepareStatement(sql1, Statement.RETURN_GENERATED_KEYS))) {
         int updateCount = pst1.executeUpdate();
         if (updateCount != 0) { // Records inserted?
             int res_id = 0; // Key
             try (ResultSet generatedKeysRS = pst1.getGeneratedKeys()) {
                  if (generatedKeysRS.next()) {
                      res_id = generatedKeysRS.getInt(1);
                  }
             }
         }
     }
    

当两个插入同时发生并且生成新生成的密钥时,这解决了并发问题:

1. A inserts
2. B inserts
3. B asks generated key
4. A asks generated key

请允许我指出两个最佳做法:

  • 代码太长,像rs1 / rs2 / rs3这样的编号会将代码暴露给混淆。尝试介绍功能。给出有意义的名字。

  • 相同的防御性编码:不要在if语句中设置 i th 列:

                                int endTask = 0;
                                int currDuration = 0;
                                String currTaskOut = "";
                                if (rs1.getLong("columnName") <= curTime) {
                                    //if (rs.getLong("columnName") > ...) {
                                    endTask = ...;
                                    currDuration = ...;
                                } else {
                                    //...
                                }
                                pst2.setLong(13, endTask);
                                pst2.setLong(14, currDuration);
                                pst2.setString(15, currTaskOut);
                                pst2.setInt(16, loop);