客户端流式传输gRPC请求时出现OutOfMemoryError

时间:2020-06-18 12:32:12

标签: android out-of-memory grpc grpc-java

我正在尝试使用客户端gRPC流上传一个大文件(165 MB)。 该文件分为2 MB的块。

val channel = AndroidChannelBuilder
    .forAddress("server address", 443)
    .context(this)
    .intercept(GrpcAuthorizationInterceptor())
    .build()

val source = FileInputStream(File("/sdcard/Movies/Movie.mp4"))

FileServiceGrpc.newStub(channel)
    .uploadFile(object : ClientResponseObserver<UploadFileRequest, UploadFileResponse> {
        override fun beforeStart(requestStream: ClientCallStreamObserver<UploadFileRequest>) {
            var counter = 0
            requestStream.setOnReadyHandler {
                while (requestStream.isReady) {
                    Log.d("MainActivity", "sending ${counter++} chunk")
                    val bytes = ByteArray(2 * 1024 * 1024)
                    source.read(bytes)
                    val byteString = ByteString.copyFrom(bytes)
                    val request = UploadFileRequest.newBuilder()
                        .setData(byteString)
                        .setExtension(UploadFileRequest.Extension.MP4)
                        .build()
                    requestStream.onNext(request)
                }
            }
        }

        override fun onNext(value: UploadFileResponse) {
        }

        override fun onError(t: Throwable) = throw t

        override fun onCompleted() {
        }
})

每次运行此代码时,应用程序都会崩溃:

java.lang.OutOfMemoryError: Failed to allocate a 24 byte allocation with 125656 free bytes and 122KB until OOM, target footprint 201326592, growth limit 201326592; failed due to fragmentation (largest possible contiguous allocation 0 bytes)

崩溃前的日志输出如下:

sending 0 chunk
...
sending 61 chunk

重要的是,每个sending x chunk日志条目之间没有延迟,这意味着setOnReadyHandler被立即调用,并且requestStream.isReady标志保持true

似乎是这里的问题:即使先前的数据尚未发送并由gRPC缓冲,isReady也会返回trueisReady方法的JavaDoc表示以下内容:

   * If {@code true}, indicates that the observer is capable of sending additional messages
   * without requiring excessive buffering internally. This value is just a suggestion and the
   * application is free to ignore it, however doing so may result in excessive buffering within the
   * observer.

android:largeHeap="true"中设置AndroidManifests.xml标志可以解决此问题,但是对我来说,这似乎只是一种解决方法。

如何改进代码以摆脱OutOfMemoryError

0 个答案:

没有答案