ChuckerTeam/chucker

OutOfMemoryError: Failed to allocate a 8208 byte allocation with 3418760 free byte

liangjingkanji opened this issue · 8 comments

✍️ Describe the bug

Downloading large files (over 150mb) crashes, I'm sure it's Chucker's problem

Exception

Throwing OutOfMemoryError "Failed to allocate a 32 byte allocation with 4673640 free bytes and 4564KB until OOM, target footprint 268435456, growth limit 268435456; failed due to fragmentation (largest possible contiguous allocation 0 bytes). Number of 256KB sized free regions are: 0" (VmSize 6440568 kB, recursive case)

Use

if (BuildConfig.DEBUG) {
    addInterceptor(
        ChuckerInterceptor.Builder(this@App)
            .collector(ChuckerCollector(this@App))
            .maxContentLength(250000L)
            .redactHeaders(emptySet())
            .alwaysReadResponseBody(false)
            .build()
    )
}

💣 Steps to reproduce

  1. Clone https://github.com/liangjingkanji/Net/tree/debug
  2. installing - Runing
  3. Wait for the download to be about 150mb
  4. Crash

🔧 Expected behavior

Do not crash when downloading large files

📷 Screenshots

image image

📱 Tech info

  • Device: Android Simulator
  • OS: Android 13
  • Chucker version: 3.5.2

📄 Additional context

I've recommended your project to others a long time ago

Downloading large files (over 150mb) crashes, I'm sure it's Chucker's problem

Can we get a reproducer of some sorts?

What do you mean? You can reproduce the problem by running the demo

I have deleted irrelevant content

Thanks for the repro @liangjingkanji
Yes I was able to reproduce with it. I'll look into it and try whenever I'll find time

I think this method returns wrong result
com.chuckerteam.chucker.internal.support.IOUtils#isPlaintext

ChuckerInterceptor will try to parse the binary, For example application/octet-stream

I think this method returns wrong result
com.chuckerteam.chucker.internal.support.IOUtils#isPlaintext

Yup that could be the reason.
Still you could have a 100Mb JSON response and Chucker will fail with a similar reason

It also fails if I upload the InputStream, Because the ChuckerInterceptor attempt will cause call RequestBody.writeTo

fun InputStream.toRequestBody(
    contentType: MediaType? = MediaConst.OCTET_STREAM,
    contentLength: Long? = null
): RequestBody {
    return object : RequestBody() {
        override fun contentType() = contentType

        val availableLength: Long by lazy {
            if (contentLength != null) return@lazy contentLength
            val availableLength = available()
            if (availableLength == 0) -1L else availableLength.toLong()
        }

        override fun contentLength(): Long {
            return availableLength
        }

        override fun writeTo(sink: BufferedSink) {
            source().use { source ->
                sink.writeAll(source)
            }
        }
    }
}

@liangjingkanji is this somethign you'll be up for attempting to fix?

Ok, I'll attempting to fix this