【发布时间】:2019-08-19 10:54:18
【问题描述】:
此代码从大约 130 MB 开始逐渐消耗内存(由于依赖关系),并在我不得不杀死它并重新启动它之前不断攀升至 800+ MB(因为服务器内存不足)。
它与 OpenJDK 11 一起运行。我在 Java 8 服务器上运行此代码的旧版本,其内存使用量保持稳定且永不增加。所以我不确定它是否与新的JDK有关?
我在这里修改了很多代码以确保它尽可能简单 - 但仍然存在问题。
基本要点 - 它是否每隔几秒钟查询一次数据库以获取待处理的发票。但是,没有待处理的发票(日志也证明了这一点),因此它永远不会进入复杂的代码位置,只会每隔几秒钟重复一次。
public static void main(String[] args) {
...
final int interval = Constants.INTERVAL;
QuickBooksInvoices qbInvoices = new QuickBooksInvoices(filename);
qbInvoices.testConnection();
log.log(Level.INFO, "Checking invoices with an interval of " + interval + " seconds...");
while (isRunning == true) {
qbInvoices.process();
try {
Thread.sleep(interval * 1000);
} catch (InterruptedException e) {
}
}
}
public void process() {
errorBuffer.clear(); // These are array lists
successBuffer.clear(); // These are array lists
try (Connection conn = DriverManager.getConnection(dbURI, dbUser, dbPassword)) {
ArrayList<com.xxx.quickbooks.model.wdg.Invoice> a = getInvoices(conn);
OAuthToken token = null;
if (a.size() > 0) {
// Never gets here - no results
}
for (com.xxx.quickbooks.model.wdg.Invoice invoice : a) {
// Never gets here - no results
}
} catch (Exception e) {
writeLog(Level.ERROR, ExceptionUtils.getStackTrace(e));
}
}
private ArrayList<com.xxx.quickbooks.model.wdg.Invoice> getInvoices(Connection conn) {
ArrayList<com.xxx.quickbooks.model.wdg.Invoice> invoices = new ArrayList<com.xxx.quickbooks.model.wdg.Invoice>();
String sql =
"select " +
"id," +
"type," +
"status," +
"business_partner_id," +
"invoice_number," +
"total," +
"nrc," +
"szrc," +
"trans_ts," +
"warehouse_id," +
"due_date," +
"ref_number," +
"payment_type " +
"FROM dv_invoice " +
"WHERE exported_ts is NULL AND exported_msg is NULL ; ";
try (
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();
) {
while (rs.next()) {
// Never gets here - no results
}
} catch (SQLException e) {
writeLog(Level.ERROR, ExceptionUtils.getStackTrace(e));
}
return invoices;
}
【问题讨论】:
-
你给Java多少内存(
-Xmx选项)? -
Profiler (YourKit, JProfiler) 或使用分析工具 (stackoverflow.com/questions/9154785/…) 以不同间隔进行堆转储。它实际上是在抛出 OOME,还是堆只是增长到允许的阈值,然后被 GC 丢弃?
-
乍一看你永远不会关闭你的
ResultSet rs,还要检查你的testConnection中是否没有任何东西可以在不关闭它们的情况下消耗资源 -
内存增长不一定是问题,但无法回收它才是问题。您是否通过多个 GC 周期长期监控它?
-
查明内存泄漏的标准过程是进行堆转储,并将其加载到 eclipse MAT 等分析工具中,以找出哪些对象被保留。然后,通常很容易找到有问题的代码。
标签: java