grp c -okhttp-3 java .lang.OutOfMemoryError: не удалось выделить 8204 байта с 3880 свободными байтами и 3 КБ до OOM - PullRequest
0 голосов
/ 29 мая 2020

Я пытаюсь загрузить файл размером более 300 МБ с помощью StreamObserver grp c, это дает следующее исключение. Я загружаю его кусками по 512 КБ.

grp c -okhttp-3 java .lang.OutOfMemoryError: не удалось выделить 8204 байта с 3880 свободными байтами и 3 КБ до OOM в okio.Segment. (Segment. java: 63) ~ [na: 0.0] в okio.SegmentPool.take (SegmentPool. java: 48) ~ [na: 0.0] в okio.Buffer.writableSegment (Buffer. java: 1211) ~ [na: 0,0] в okio.Buffer.writeByte (Buffer. java: 1069) ~ [na: 0,0] в okio.RealBufferedSink.writeByte (RealBufferedSink. java: 124 ) ~ [na: 0.0] в io.grp c .okhttp.internal.framed.Http2.writeMedium (Http2. java: 773) ~ [na: 0.0] в io.grp c .okhttp.internal .framed.Http2.access $ 600 (Http2. java: 47) ~ [na: 0.0] в io.grp c .okhttp.internal.framed.Http2 $ Writer.frameHeader (Http2. java: 578) ~ [na: 0.0] в io.grp c .okhttp.internal.framed.Http2 $ Writer.dataFrame (Http2. java: 498) ~ [na: 0.0] в io.grp c .okhttp. internal.framed.Http2 $ Writer.data (Http2. java: 493) ~ [na: 0.0] в io.grp c .okhttp.AsyncFrameWriter $ 9.doRun (AsyncFrameWriter. java: 148) ~ [na: 0.0] at io.grp c .okhttp.AsyncFrameWriter $ WriteRunnable.run (AsyncFrameWriter. java: 220) ~ [na: 0.0] at io.grp c .internal.SerializingExecutor.run ( SerializingExecutor. java: 123) ~ [na: 0,0] в java .util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor. java: 1133) ~ [na: 0,0] в java .util.concurrent. ThreadPoolExecutor $ Worker.run (ThreadPoolExecutor. java: 607) ~ [na: 0,0] в java .lang.Thread.run (Thread. java: 761) ~ [na: 0,0]

BufferedInputStream bInputStream = new BufferedInputStream(new FileInputStream(file));

try {

int bufferSize = 512; // 512k
byte[] buffer = new byte[bufferSize];
long size = 0, originalSize = file.length();
int chunk;
do {
chunk = bInputStream.read(buffer);
size += chunk;
if (chunk > 0) {
ByteString byteString = null;
if (chunk < 512) {
byte[] remaining = Arrays.copyOfRange(buffer, 0, chunk);
byteString = ByteString.copyFrom(remaining);
 } else {
byteString = ByteString.copyFrom(buffer);
}
putRequestStreamObserver.onNext(FileUploadRequest.newBuilder()
.setFileChunk(FileChunk.newBuilder()
.setChunk(byteString)
.build())
.build());

logger.info("New Chunk!");

У меня в манифесте указаны android:hardwareAccelerated="false" и android:largeHeap="true".

1 Ответ

1 голос
/ 01 июня 2020

Поскольку StreamObserver API асинхронный, он может вернуться до отправки сообщения. Если вы отправите слишком быстро, они будут буферизироваться локально.

Вам необходимо соблюдать контроль потока / противодавление. Вы должны создать ClientResponseObserver, чтобы получить ClientCallStreamObserver и позвонить setOnReadyHandler() в beforeStart(). Затем вы захотите наблюдать isReady() и не отправлять, когда он становится false. См. Пример manualflowcontrol ; можно игнорировать disableAutoInboundFlowControl() / request() штук; то есть для получения, а не для отправки.

...