1

I'm trying to send a file (a video here) to my server with an ssl socket, I can send it 11 times, but when I try one more time I had an OutOfMemoryError, and I would want to know how to fix this.

Client side (Android) :

    InputStream inputStream = null;
    try {
        inputStream = getAssets().open("test.mp4");
    } catch (IOException e) {
        e.printStackTrace();
    }

    byte[] bytes2 = null;

    try {
        bytes2 = getBytes(inputStream);
    } catch (IOException e) {
        e.printStackTrace();
    }

    if (socketConnect()) {
        try {
            Log.d("MainActivity", "Before OutputStream");
            OutputStream os = sock.getOutputStream();
            Log.d("MainActivity", "Before FileInputStream");
            Log.d("MainActivity", "Before while " + bytes2.length);
            os.write(bytes2);
            Log.d("MainActivity", "After while");
            os.flush();
            os.close();
            sock.close();
            Log.d("MainActivity", "End");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    else {
        Log.e("MainActivity", "Erreur");
    }

Server side (Python) :

import socket
import sys
import ssl


sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(("",9999))

sock.listen(10)

i=1

while True:
    (clientsocket, (ip, port)) = sock.accept()
    connstream = ssl.wrap_socket(clientsocket,
                                 server_side = True,
                                 certfile = "server.crt",
                                 keyfile = "server.key")
    f = open('test_'+str(i)+".jpg",'wb') #open in binary
    i=i+1
    print(i)
    l = 1
    l = connstream.read(1024)

    while (l):
            print("toto")
            f.write(l)
            l = connstream.read(1024)
    f.close()

    connstream.close()

sock.close()

Log :

05-28 09:56:31.019 11519-11519/com.youstiti.simon.testenvoiwithbuffer E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.youstiti.simon.testenvoiwithbuffer, PID: 11519
java.lang.OutOfMemoryError: Failed to allocate a 33552396 byte allocation with 28973408 free bytes and 27MB until OOM
    at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:91)
    at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:201)
    at com.youstiti.simon.testenvoiwithbuffer.MainActivity.getBytes(MainActivity.java:153)
    at com.youstiti.simon.testenvoiwithbuffer.MainActivity.onCreate(MainActivity.java:73)
    at android.app.Activity.performCreate(Activity.java:6272)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2387)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2494)
    at android.app.ActivityThread.access$900(ActivityThread.java:157)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1356)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5525)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)

I think a buffer can solve the problem, but I don't know how to do it.

Thanks for your answers

J.Doe
  • 45
  • 5

1 Answers1

0

You have to read and send your file chunk by chunk to avoid OOM error, because the android heap is limited, something like below

if (socketConnect()) {
try {
    final int bufferSize = 8*1024;
    FileInputStream fis = new FileInputStream(/*...your file*/);
    byte[] buffer = new byte[bufferSize]; 
    int read;
    OutputStream os = sock.getOutputStream();
    while( ( read = fis.read( buffer ) ) > 0 ){
          os.write(buffer, 0, read);
    }
    os.close();
    fis.close();    
} catch (IOException e) {
    e.printStackTrace();
}
else {
    Log.e("MainActivity", "Erreur");
}

Avoid to request a large heap by adding android:largeHeap="true", google said :

Never request a large heap simply because you've run out of memory and you need a quick fix

Take a look at the doc for more

user207421
  • 305,947
  • 44
  • 307
  • 483
E.Abdel
  • 1,992
  • 1
  • 13
  • 24
  • 1
    `os.write(buffer)` is not correct. It ignores the count returned by `read()`, and will write junk at the end of the input, if not before. It should be `os.write(buffer, 0, read)`. The buffer size of 1MB is a couple of orders of magnitude too large. – user207421 May 28 '18 at 08:42
  • 1
    OK. You should not flush inside loops. It destroys the point of any buffering that may be present: which in this case is none. Fixed that and several other issues. – user207421 May 28 '18 at 08:49
  • At the line: FileInputStream fis = new FileInputStream(/*...your file*/); I have to put the file path right ? – J.Doe May 28 '18 at 09:10
  • Thanks for your answer. When I put the file, that doesn't work, but when I put the path of the file, it work (with an image), but when I want to send a video, I have the outOfMemoryError – J.Doe May 28 '18 at 09:37
  • Ok, my bad, its working with File, but I always have the outOfMemoryError with a video – J.Doe May 28 '18 at 09:47
  • No and it's just a video of 10 sec – J.Doe May 28 '18 at 10:06
  • `my bad, its working with File, but I always have the outOfMemoryError with a video` ??? Nonsense! Where are you talking about? If you can upload a file then you can also upload a video file. It is nonsense as you cannot compare the File class with a video. And you have to use full file path every time. Please tell the paths. – greenapps May 28 '18 at 10:17
  • Ok, the problem come from a log, now it work fine ! Thank you so much ! – J.Doe May 28 '18 at 10:19
  • A socket output stream is not buffered. Even if it was, you should not flush inside the loop. Otherwise there is no advantage from any buffering that may exist. As I already stated. You should flush, or close. *after* the loop. This is self-evident. – user207421 May 28 '18 at 11:31
  • Thanks for all your answer – J.Doe May 28 '18 at 12:07