代码之家  ›  专栏  ›  技术社区  ›  Piotr Aleksander Chmielowski

客户端流式处理gRPC请求时发生OutOfMemoryError

  •  0
  • Piotr Aleksander Chmielowski  · 技术社区  · 4 年前

    文件被分为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 退货 . 的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 回复  |  直到 4 年前