2014-12-08 4 views
1

나는 부채 상환 계산기에 대해 수십 번 루프를 반복 할 수 있습니다. 이 루프가하는 여러 가지의메모리 부족 오류 문자열에 실패

하나는 내가 문자열 (쿼리) check_for_special를 구축 행에서이 OutOfMemory 스택 트레이스를 얻고있다 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; 
    } 
} 

라는 메소드를 호출합니다.

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

답변

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;"); 

같은.

이 말은 여러분이 너무 많은 메모리를 사용하고 있다는 것입니다.이 메모리는 너무 단순하고 메모리 부족을 시도 할 때 메모리가 부족합니다.

힙 덤프를 생성하고 가장 큰 메모리 위반자를 찾으십시오.

+1

동의 함,이 함수 내에서 생성 된 모든 객체 (눈을 가리고 "수십 번"이라고 함)를 자세히 살펴 봅니다. 예를 들어 CalendarInstance 및 SimpleDateFormat은 한 번 생성되어 다시 사용될 수 있습니다. 또한 문자열 (예 : http://stackoverflow.com/questions/9857073/queries-with-prepared-statements-in-android)에서 rawQuery 대신 매개 변수화 된 쿼리를 고려해보십시오. 단일 쿼리 문자열 인 – CSmith

+0

알았어 고마워. 이걸 사냥해서 메모리 모니터 도구를 사용하는 법을 배워야 할 것 같네요. – KickingLettuce

+0

@KickingLettuce Eclipse MAT를 사용하는 것이 좋습니다. 정말 사용하기 쉽습니다. jmap은 내가 힙 덤프에 사용하는 것이다. –