Reputation: 15734
I have a loop that can loop dozens of times for a debt payoff calculator.
One of the many things this loop does is call a method called 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;
}
}
I am getting this OutOfMemory
stacktrace on the line that build the String (the query) 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
I don't understand why a String
initialization would cause the failure; or is this a coincidence where a bigger problem has simply failed at this point?
EDIT:
This picture is of my Heap Dump:
Upvotes: 1
Views: 1489
Reputation: 40256
You have a larger problem on your hand here. The OOM error caused by getSpecialPayment
is symptomatic of memory leaking elsewhere.
Some context, this line here
String check_for_special = "SELECT payment FROM special_payments WHERE id = " + debt_id + " and month = '" + sMonth + "' LIMIT 1;";
really will do something like
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;");
That's all compiled away so you don't see it without stepping through the code.
What this is telling you, is that you are using up so much memory which is not being reclaimed that when you try to do something simple and low memory like this, it is running out of memory.
I suggest creating a heap dump and try to find the greatest offenders of memory.
Upvotes: 2