

Listを設定したUnityWebRequest.uploadHandlerのメモリリーク

Unityで開発を行っております。  
環境はUnity 2018.4.22f1になります。  
ファイルをアップロードするために以下のコードを作成しました。

[code]

    // ファイル読み込み
    byte[] l_file_data = File.ReadAllBytes( _path );
    string l_fileName = "hoge.mp4";
    
    var request = new UnityWebRequest( l_url, "POST");
    setRequest( request );
    // タイムアウト設定
    request.timeout = 300;
    
    List<IMultipartFormSection> requestData = new List<IMultipartFormSection>();
    requestData.Add( new MultipartFormFileSection( "file", l_file_data, l_fileName, "video/*" ) );
    
    if( 0 < user_id )
        requestData.Add( new MultipartFormDataSection( "user_id",               user_id.ToString() ) );
    if( 0 < player_id )
        requestData.Add( new MultipartFormDataSection( "player_id",             player_id.ToString() ) );
    if( 0 < group_id )
        requestData.Add( new MultipartFormDataSection( "group_id",              group_id.ToString() ) );
    if( 0 < team_id )
        requestData.Add( new MultipartFormDataSection( "team_id",               team_id.ToString() ) );
    if( 0 < game_id )
        requestData.Add( new MultipartFormDataSection( "game_id",               game_id.ToString() ) );
    
    if( !title.Equals( "" ) )
        requestData.Add( new MultipartFormDataSection( "title",                 System.Text.Encoding.UTF8.GetBytes( title ) ) );
    if( !comment.Equals( "" ) )
        requestData.Add( new MultipartFormDataSection( "comment",               System.Text.Encoding.UTF8.GetBytes( comment ) ) );
    
    byte[] boundary = UnityWebRequest.GenerateBoundary();
    byte[] formSections = UnityWebRequest.SerializeFormSections( requestData, boundary );
    
    // データ設定
    request.uploadHandler   = (UploadHandler) new UploadHandlerRaw( formSections );
    request.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
     
    // ヘッダを設定
    request.SetRequestHeader("X-Requested-With", "XMLHttpRequest" );
    request.SetRequestHeader("Content-Type", "multipart/form-data; boundary="+System.Text.Encoding.UTF8.GetString(boundary) );
    request.SetRequestHeader( "Authorization", "Bearer "+ _access_token );
    // アプリ名、Ver、プラットフォーム
    request.SetRequestHeader("X-Escore-Env", "app="+APP_NAME+"; ver="+VER+"; os="+isOS() );
    
    yield return request.Send();
    
[/code]

このコードで120MBほどのファイルをアップロードする際にWindowsエディター上ではメモリの異常増加は見られなかったのですが、  
iPad上で確認した際にメモリが800MB以上増えメモリリークが発生しました。

ファイル自体は120MBですが、なぜここまで使用メモリーが増えるのでしょうか。  
こちら改善方法をご存じでしょうか。  
UnityのVerアップも考えておりますが、そちらで解決できるのでしょうか。

よろしくお願い致します。


CC BY-SA 4.0
2021-03-29T01:08:32.290
74953
2021-03-29T11:42:11.157
29606
question
ios xcode unity2d
List<IMultipartFormSection>を設定したUnityWebRequest.uploadHandlerのメモリリーク


メモリを浪費していると思われる箇所が、いくつかあります。

[code]

    byte[] formSections = UnityWebRequest.SerializeFormSections( requestData, boundary );
    
[/code]

この処理は、マルチパートのデータをまとめて一つのメッセージボディのためのデータにする処理です。  
まとめるわけですから、出来上がるデータ(`formSections`)のサイズは、元のデータの合計よりも多くなると思われますので、この時点で120M以上のバイト配列が2つ存在することになります。

更に、`UnityEngine.Networking.UploadHandlerRaw`ですが、[マニュアル](https://docs.unity3d.com/ja/2018.4/ScriptReference/Networking.UploadHandlerRaw.html)には以下のように書かれています。

> このサブクラスは **コンストラクション時にネイティブコードのメモリバッファーに入力データをコピーし** 、 HTTP
> リクエストボディデータとしてデータそのままを送信します。

この言葉を素直に受け取れば、`UploadHandlerRaw`のコンストラクタでも同サイズのバッファが使われている可能性があります。

対策としては、[`UploadHandlerFile`](https://docs.unity3d.com/ja/2018.4/ScriptReference/Networking.UploadHandlerFile.html)を使うことを検討してください。  
マニュアルにも、「You can use it to send a large amount of data to the server with a
low memory footprint.」と書かれています。  
ただし、一度に遅れるのは一つのファイルのみで、他のデータを一緒に送ることはできなさそうです。

もしそれがダメであれば、`UnityWebRequest.SerializeFormSections`を使わないとか、そもそも`UnityWebRequest`を使わないとか、考えなければなりません。


CC BY-SA 4.0
2021-03-29T11:42:11.157
74967
2021-03-29T11:42:11.157
15473
74953
answer