首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 打開 PDF 導致 OOM 內存洩漏排查:Activity 銷毀與後台線程生命周期不一致

     編輯:程式設計綜合問答

問題代碼分析

ByteArrayOutputStream f = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) > 0) {
    f.write(buffer, 0, len); // PDF 較大時 f 無限增長,佔用巨大堆內存
}

洩漏根因

  1. 全量讀入內存:ByteArrayOutputStream 將整個 PDF 字節流緩存在堆中,大文件直接 OOM。
  2. Activity 未正確銷毀:若打開 PDF 的 Activity 在返回時未 finish(),或被單例/靜態變量持有,導致其持有的 f 無法回收。
  3. 後台線程持有引用:解析 PDF 的異步線程運行中,Activity 已銷毀但線程未結束,繼續持有 f、buffer 等對象。

解決方案

方案一:流式處理,不全量緩存

// 使用 PdfRenderer (API 21+) 頁面級渲染
PdfRenderer renderer = new PdfRenderer(ParcelFileDescriptor.open(file, MODE_READ_ONLY));
for (int i = 0; i < renderer.getPageCount(); i++) {
    PdfRenderer.Page page = renderer.openPage(i);
    Bitmap bitmap = Bitmap.createBitmap(page.getWidth(), page.getHeight(), Bitmap.Config.ARGB_8888);
    page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
    // 顯示 bitmap 到 ImageView
    page.close();
}
renderer.close();

方案三:生命周期綁定取消

// 在 onDestroy 中取消異步任務
@Override
protected void onDestroy() {
    super.onDestroy();
    if (pdfTask != null) pdfTask.cancel(true);
    // 釋放大對象引用
    pdfStream = null; buffer = null;
}

檢查清單

  • 使用 LeakCanary 或 Android Studio Profiler 定位洩漏對象。
  • 確認 Activity onDestroy 執行,無靜態/單例持有 Context。
  • 大文件處理採用流式/分頁,避免一次性載入堆內存。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved