字符串失败的内存不足错误

时间:2014-12-08 19:59:58

标签: java android out-of-memory

我有一个循环,可以为债务支付计算器循环数十次。

此循环执行的许多操作之一是调用名为getSpecialPayment

的方法
  private double getSpecialPayment(long debt_id, int month) {

    int thisMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;

    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.MONTH, month + thisMonth);

    SimpleDateFormat df = new SimpleDateFormat("MMM yyyy", Locale.ENGLISH);
    String sMonth = df.format(cal.getTime());

    // Line 884 that fails below 
    String check_for_special = "SELECT payment FROM special_payments WHERE id = " + debt_id + " and month = '" + sMonth + "' LIMIT 1;"; 

    if (!database.isOpen()) {
        open();
    }

    Cursor c = database.rawQuery(check_for_special, null);
    if (c.getCount() == 0) {
        c.close();
        return 0;
    } else {
        c.moveToFirst();
        double amount = c.getDouble(c.getColumnIndex("payment"));
        c.close();
        return amount;
    }
}

我在构建String(查询)OutOfMemory的行上获得此check_for_special堆栈跟踪。

java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.OutOfMemoryError
at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:94)
at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:145)
at java.lang.StringBuilder.append(StringBuilder.java:216)
at com.---.---.DebtDataSource.getSpecialPayment(DebtDataSource.java:884)
at com.---.---.DebtDataSource.payoffDebt(DebtDataSource.java:469)
at com.---.---.PlannerFragment$PlannerTask.doInBackground(PlannerFragment.java:156)
at com.---.---.PlannerFragment$PlannerTask.doInBackground(PlannerFragment.java:122)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
... 4 more

我不明白为什么String初始化会导致失败;或者这是一个巧合,在这一点上更大的问题根本就失败了?

修改

这张照片是我的堆转储:

enter image description here

1 个答案:

答案 0 :(得分:2)

你手上有一个更大的问题。由getSpecialPayment引起的OOM错误是其他地方内存泄漏的症状。

一些上下文,这一行

String check_for_special = "SELECT payment FROM special_payments WHERE id = " + debt_id + " and month = '" + sMonth + "' LIMIT 1;";

真的会做类似

的事情
StringBuilder builder = new StringBuilder("SELECT payment FROM special_payments WHERE id = ");
builder.append(debt_id);
builder.append("and month = '");
builder.append(sMonth);
builder.append(' LIMIT 1;");

所有这些都被编译掉了,所以如果没有单步执行代码,你就不会看到它。

这告诉你的是,你正在耗尽如此多的内存,而这些内存并没有被回收,当你尝试做一些像这样简单且内存不足的内存时,内存已经不足了。

我建议创建一个堆转储并尝试找到最大的内存违规者。