android, Volley 를 이용한 동영상 업로드 테스트 결과. |
테스트 환경
국내 android major 단말들이라고 할 수 있는 Galaxy S 시리즈와 Note 1 을 대상으로 삼았다.
동영상 업로드 방법은 Volley 와 MultipartRequest 를 이용한 일시 업로드이다.
Galaxy S / hdpi / 2.3.4
-
12.5M 동영상 ( 30초 )
-
process mem = 64MB
runtime maxMemory = 64MB
runtime totalMemory = 5MB
runtime freeMemory = 2MB
native threshold = 26MB
native availMem = 83MB
-
Out of memory on a 26310336-byte allocation.
java.lang.OutOfMemoryError
at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:91)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:216)
at org.apache.harmony.luni.internal.net.www.protocol.http.RetryableOutputStream.write(RetryableOutputStream.java:60)
at java.io.DataOutputStream.write(DataOutputStream.java:99)
at java.io.FilterOutputStream.write(FilterOutputStream.java:105)
at com.android.volley.toolbox.HurlStack.addBodyIfExists(HurlStack.java:244)
at com.android.volley.toolbox.HurlStack.setConnectionParametersForRequest(HurlStack.java:226)
at com.android.volley.toolbox.HurlStack.performRequest(HurlStack.java:108)
at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:93)
at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:105)
-
OOM 을 초래하는 Allocation 된 memory 를 보니, 약 26MB 로 native threshold 와 일치한다.
가용 가능한 native memory 가 83MB 인데, native threshold 가 26MB 인걸로 보아, 가용 native memory 가 높아도 앱에 허용되는 native memory 는 native threshold 로 제한되는 모양이다.
-
동영상 용량이 12.5MB 인데 약 2배의 메모리를 가용하는 것으로 보아,
MultipartRequest 를 작성할 때 Multipart body 에 byte 코드로 1회 로딩하고,
Volley 대부에서 request body 에 다시 한번 이 내용을 쓰는 과정에서 byte 코드를 복사하므로,
2배의 메모리를 사용하는 것으로 보인다.
GALAXY S2 / hdpi / 4.1.2
-
43.25M 동영상 ( 30초 )
-
process mem = 48MB
runtime maxMemory = 128MB
runtime totalMemory = 13MB
runtime freeMemory = 1MB
native threshold = 64MB
native availMem = 243MB
-
Out of memory on a 67101078-byte allocation.
FATAL EXCEPTION: Thread-1177
java.lang.OutOfMemoryError
at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:91)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:201)
at org.apache.http.entity.mime.content.FileBody.writeTo(FileBody.java:97)
at org.apache.http.entity.mime.HttpMultipart.doWriteTo(HttpMultipart.java:206)
at org.apache.http.entity.mime.HttpMultipart.writeTo(HttpMultipart.java:224)
at org.apache.http.entity.mime.MultipartEntity.writeTo(MultipartEntity.java:183)
at com.imcompany.school2.rest.MultipartRequest.getBody(MultipartRequest.java:92)
at com.android.volley.toolbox.HurlStack.addBodyIfExists(HurlStack.java:239)
at com.android.volley.toolbox.HurlStack.setConnectionParametersForRequest(HurlStack.java:226)
at com.android.volley.toolbox.HurlStack.performRequest(HurlStack.java:108)
at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:93)
at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:105)
-
마찬가지로 native threshold 가 limit 가 되었다.
-
용량이 43.25MB 인걸로 보아
첫번째 multipart body 에 write 는 성공했지만, volley 내부의 request body 에 copy 하던 과정에서 두배인 약 86MB 가 안 되었어도,
threshold 를 넘었기 때문에 OOM 이 발생한 것으로 보인다.
Galaxy S3 / xhdpi / 4.1.2
-
61.0M 동영상 ( 30초 )
-
process mem = 64MB
runtime maxMemory = 256MB
runtime totalMemory = 203MB
runtime freeMemory = 186MB
native threshold = 64MB
native availMem = 781MB
-
no error.
-
Galaxy S3 는 그래도 나름 최신 framework 를 가지고 있어서인지,
똑같은 로직이라면 61MB 동영상을 올리는 과정에서 native threshold 가 64MB 이기 때문에
같은 OOM 을 방출해야 하는데 이를 방출하지 않았다.
왜인지 정말 궁금하지만, 지금 생각할 수 있는 것은 native framework 의 http 관련 library update 로밖에 생각을 못하겠다..
아 궁금해!!
Galaxy Note / xhdpi / 4.0.4
-
43.8M 동영상 ( 30초 )
-
process mem = 64MB
runtime maxMemory = 148MB
runtime totalMemory = 15MB
runtime freeMemory = 0MB
native threshold = 80MB
native availMem = 142MB
-
Out of memory on a 91892526-byte allocation.
FATAL EXCEPTION: Thread-921
java.lang.OutOfMemoryError
at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:91)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:201)
at libcore.net.http.RetryableOutputStream.write(RetryableOutputStream.java:61)
at java.io.DataOutputStream.write(DataOutputStream.java:98)
at java.io.OutputStream.write(OutputStream.java:82)
at com.android.volley.toolbox.HurlStack.addBodyIfExists(HurlStack.java:244)
at com.android.volley.toolbox.HurlStack.setConnectionParametersForRequest(HurlStack.java:226)
at com.android.volley.toolbox.HurlStack.performRequest(HurlStack.java:108)
at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:93)
at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:105)
해결책
-
해결책은 Volley & Multipart request 를 이용하여 2중으로 memory 를 사용하는 것이 아닌,
기본 HttpClient 와 같은 녀석들을 써서 inputstream 을 이용한 분할 업로딩을 하는 방법이 있겠다.
-
두번째 해결책은 server side 에서 분할 업로드를 추가 지원하는 방식으로,
여러번에 걸쳐서 multipart request 를 호출하며, packet 번호를 함께 전송하는 방식으로 하면 되겠다.
-
stream 전송은 보통 서버에서 기본 지원하는 녀석으로 httpclient 등을 이용해서 stream 전송을 할줄만 안다면 첫번째 방법이 훨씬 general 하며 쉬운 방법이다.
댓글