使用FileOutputStream写入文件时遭遇偶发OutOfMemoryError求助
问题分析与解决方案
核心问题
- 递归死循环触发OOM:写入文件抛出
IOException时,catch块调用debug(),而debug()又会触发writeFile(),形成无限递归。每次递归都会生成新的字符串、字节数组,持续消耗内存直到触发OutOfMemoryError。 - 内存开销累积:每次写入都通过
formatLog()生成字符串再转ByteArray,频繁的对象创建在循环中会快速耗尽可用内存。
具体修复步骤
1. 打破递归死循环
修改writeFile的异常捕获逻辑,禁止在catch块中调用会触发写入的debug(),改用Logcat输出错误:
private fun writeFile(tag: String, msg: String, exception: Throwable?) { try { logFileOutputStream?.let { outputStream -> outputStream.write(formatLog(msg).toByteArray()) outputStream.flush() } } catch (e: IOException) { // 改用Logcat输出,避免触发递归写入 android.util.Log.e(TAG, "写入日志失败: $msg, 错误信息: ${e.message}") } }
2. 优化内存使用
用BufferedWriter包装输出流,直接写入字符串,避免频繁的String转ByteArray操作,减少内存开销:
// 初始化时替换FileOutputStream为BufferedWriter private var logWriter: BufferedWriter? = null // 初始化示例 fun initLogFile(file: File) { try { logWriter = BufferedWriter(FileWriter(file, true)) } catch (e: IOException) { android.util.Log.e(TAG, "初始化日志文件失败: ${e.message}") } } private fun writeFile(tag: String, msg: String, exception: Throwable?) { try { logWriter?.let { writer -> writer.write(formatLog(msg)) writer.flush() } } catch (e: IOException) { android.util.Log.e(TAG, "写入日志失败: $msg, 错误信息: ${e.message}") } } private fun formatLog(msg: String): String { val dateTime = DateFormatterUtility.formatDateTimeToString(Date(), "MM/dd/yyyy HH:mm:ss.SSS") return "$dateTime : $msg\n" }
3. 额外防护措施
- 写入前检查日志文件状态:确认文件存在、可写,以及剩余磁盘空间充足。
- 限制单条日志长度:对超大内容的日志进行拆分或截断,避免一次性占用过多内存。
- 增加OOM异常捕获作为最后防线:
private fun writeFile(tag: String, msg: String, exception: Throwable?) { try { logWriter?.let { writer -> writer.write(formatLog(msg)) writer.flush() } } catch (e: IOException) { android.util.Log.e(TAG, "写入日志失败: $msg, 错误信息: ${e.message}") } catch (e: OutOfMemoryError) { android.util.Log.e(TAG, "内存不足,无法写入日志") // 可考虑释放部分资源或暂时停止日志写入 } }
内容的提问来源于stack exchange,提问作者Anshul Tyagi
相关产品推荐
相关产品推荐

