Java / Derby - 我应该自己管理应用程序内存吗?

时间:2014-08-06 07:55:28

标签: java memory jdbc out-of-memory derby

我在NetBeans中编写了这个简单的类,以便了解如何通过Java代码连接和管理Derby数据库,并使用IDE提供的示例数据库作为连接目标。我相信它是一个相当简单的数据库连接示例:

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;


public class MainClass {

    public static void main(String[] args) {

        //Some code that allows me to start the connection only after keyboard input
        System.out.println("Program will now connect to database");
        try {
            System.in.read();
        }
        catch (IOException ex) {
            Logger.getLogger(MainClass.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Redirecting DriverManager's output to the console's standard output
        DriverManager.setLogWriter(new PrintWriter(System.out));

        // This is where I connect to the database, execute a query and print a result
        // Still barebones, I am learning SQL basics yet
        String dbURL ="jdbc:derby:C:\\users\\project2100\\.netbeans-derby\\sample";
        try (Connection conn = DriverManager.getConnection(dbURL, "app", "app")) {
            System.out.println("Connected");

            try (Statement stmt = conn.createStatement()) {
                ResultSet output = stmt.executeQuery("SELECT * FROM CUSTOMER");
                while (output.next()) {
                    System.out.println(output.getString("NAME"));
                }
            }
        }
        catch (SQLException ex) {
            Logger.getLogger(MainClass.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Recently added to keep the application alive
        // This way, I can monitor memory usage on Task Manager
        try {
            System.in.read();
        }
        catch (IOException ex) {
            Logger.getLogger(MainClass.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Java的标准输出为我提供了我期望的结果,但DriverManager的输出告诉了我一些令人担忧的事情;这是应用程序运行的完整控制台输出:

run:
Program will now connect to database

DriverManager.getConnection("jdbc:derby:C:\users\project2100\.netbeans-derby\sample")
    trying org.apache.derby.jdbc.AutoloadedDriver40
SQLState(08004) vendor code(40000)
java.sql.SQLException: Connection refused : java.lang.OutOfMemoryError
    at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
    at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedConnection.<clinit>(Unknown Source)
    at org.apache.derby.jdbc.InternalDriver.connect(Unknown Source)
    at org.apache.derby.jdbc.Driver20.connect(Unknown Source)
    at org.apache.derby.jdbc.AutoloadedDriver.connect(Unknown Source)
    at java.sql.DriverManager.getConnection(DriverManager.java:664)
    at java.sql.DriverManager.getConnection(DriverManager.java:247)
    at javadbpg.MainClass.main(MainClass.java:35)
SQLState(08004) vendor code(40000)
java.sql.SQLNonTransientConnectionException: Connection refused : java.lang.OutOfMemoryError
    at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedConnection.<clinit>(Unknown Source)
    at org.apache.derby.jdbc.InternalDriver.connect(Unknown Source)
    at org.apache.derby.jdbc.Driver20.connect(Unknown Source)
    at org.apache.derby.jdbc.AutoloadedDriver.connect(Unknown Source)
    at java.sql.DriverManager.getConnection(DriverManager.java:664)
    at java.sql.DriverManager.getConnection(DriverManager.java:247)
    at javadbpg.MainClass.main(MainClass.java:35)
Caused by: java.sql.SQLException: Connection refused : java.lang.OutOfMemoryError
    at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
    ... 11 more
getConnection returning org.apache.derby.jdbc.AutoloadedDriver40
Connected
Jumbo Eagle Corp
New Enterprises
Wren Computers
Small Bill Company
Bob Hosting Corp.
Early CentralComp
John Valley Computers
Big Network Systems
West Valley Inc.
Zed Motor Co
Big Car Parts
Old Media Productions
Yankee Computer Repair Ltd

BUILD SUCCESSFUL (total time: 23 seconds)

注意:前两个错误之间有1-2秒的挂起。

就在最近,在浏览了互联网上可能导致这些OutOfMemoryError的原因之后,我添加了最后try块,并观察了应用程序的内存占用情况。它从最初的~9MB到~40MB。

因此,我应该在应用程序中设置一些内存参数,以减少这些错误,并最终获得性能? (如果是这样,我可以提供一些指示吗?)或者我应该保留所有内容并让DriverManager单独工作?

2014-08-07后续行动:

这一次,我在调试模式下运行应用程序,并逐步记下私有内存使用情况。兴趣点如下:

  • try (Connection conn = ...语句之前的内存金额为12MB;
  • 在此之后,该程序会挂起约5秒并触发上述所有OutOfMemoryErrors;
  • 经过5秒后,程序在<{em> System.out.println("Connected");声明之前保留37MB 的总内存;
  • executeQuery语句又增加了7MB,总计:45MB。执行时间可以忽略不计(<1/2秒);

这里是Bryan Pendleton要求的derby.log文件,其状态是在之前的所有测试之后:

----------------------------------------------------------------
Thu Aug 07 10:10:11 CEST 2014:
Booting Derby version The Apache Software Foundation - Apache Derby - 10.10.1.3 - (1557168): instance a816c00e-0147-af84-a381-0000263f2b92 
on database directory C:\Users\Project2100\.netbeans-derby\C3Subjects with class loader sun.misc.Launcher$AppClassLoader@58644d46 
Loaded from file:/C:/Program%20Files/Java/jdk1.8.0_05/db/lib/derby.jar
java.vendor=Oracle Corporation
java.runtime.version=1.8.0_05-b13
user.dir=C:\Users\Project2100\Documents\NetBeansProjects\JavaDB Proving Grounds
os.name=Windows 7
os.arch=amd64
os.version=6.1
derby.system.home=C:\users\Project2100\.netbeans-derby
Database Class Loader started - derby.database.classpath=''

昨天,我一直在互联网上搜索有关内存管理的问题,并尝试使用CLI参数-Xms-Xns来提升应用程序的启动内存,但无济于事;这些选项仅操作应用程序的保留内存,并使最初使用的实际内存保留在通常的9-10MB。无论如何,我得到了相同的内存值,错误和挂起。

我想,就目前而言,我将在loading database...下粉笔这种行为并继续使用SQL本身,因为系统控制台根本没有列出任何投诉。但是,如果确实有一种方法可以预先在数据库连接上分配更多内存,那么我很感激能够得到答案。

非常感谢你的帮助!

1 个答案:

答案 0 :(得分:0)

org.apache.derby.impl.jdbc.EmbedConnection中有一个静态变量:

/**
 * Static exception to be thrown when a Connection request can not
 * be fulfilled due to lack of memory. A static exception as the lack
 * of memory would most likely cause another OutOfMemoryException and
 * if there is not enough memory to create the OOME exception then something
 * like the VM dying could occur. Simpler just to throw a static.
 */
public static final SQLException NO_MEM =
    newSQLException(SQLState.LOGIN_FAILED, "java.lang.OutOfMemoryError");

为DriverManager设置logwriter时,将打印SQLException:

public SQLException(String reason, String SQLState, int vendorCode) {
    super(reason);
    this.SQLState = SQLState;
    this.vendorCode = vendorCode;
    if (!(this instanceof SQLWarning)) {
        if (DriverManager.getLogWriter() != null) {
            DriverManager.println("SQLState(" + SQLState +
                                            ") vendor code(" + vendorCode + ")");
            printStackTrace(DriverManager.getLogWriter());
        }
    }
}

这就是为什么我们有一个难看的堆栈跟踪。