Я пытаюсь загрузить большой файл (165 МБ), используя клиентскую потоковую передачу gRP C. Файл разбит на фрагменты по 2 МБ.
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)
Вывод журнала перед cra sh выглядит следующим образом :
sending 0 chunk
...
sending 61 chunk
Что важно, нет задержки между каждой sending x chunk
записью журнала, что означает, что setOnReadyHandler
вызывается немедленно, а флаг requestStream.isReady
остается true
.
Похоже, вот в чем проблема: хотя предыдущие данные не были отправлены и буферизированы gRP C, isReady
возвращает true
. Метод JavaDo c of isReady
говорит следующее:
* 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
?