1

初めて非同期タスクを実行すると正常に動作します。実際、このエラーは予期せず発生します。私はこの問題について多くの解決策を探しますが、私にとっては何も効果がありません。 私が持っている共通の解決策は、私たちはInputStream/ByteArrayInputStreamを閉じる必要があります&私はまだすべてを閉じたが、まだアプリはクラッシュします。java.lang.OutOfMemoryError:JNI Envを割り当てることができませんでした

スタックトレース:

java.lang.OutOfMemoryError: Could not allocate JNI Env at java.lang.Thread.nativeCreate(Native Method) at java.lang.Thread.start(Thread.java:730) at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:941) at java.util.concurrent.ThreadPoolExecutor.processWorkerExit(ThreadPoolExecutor.java:1009) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1151) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) at java.lang.Thread.run(Thread.java:761)

後はAsyncTaskです。続き

public class AsyncHttpRequest extends AsyncTask<Void, Void, String> { 

    private String UrlString = ""; 
    private boolean _showProgressDialog = false; 
    private CustomCircularLoadingDialog Dialog; 
    private Context mContext; 
    AppCompatActivity mActivity; 
    private IHttpRequestCompletedListener listener; 
    private boolean isActivity = true; 
    private String _messageText = "Please wait..."; 
    private String type = "get"; 

    private HttpUtility utility; 


    public AsyncHttpRequest(String urlString, Context context, IHttpRequestCompletedListener listener, boolean _showProgressDialog) { 
     UrlString = urlString; 
     this._showProgressDialog = _showProgressDialog; 
     this.mContext = context; 
     this.listener = listener; 
     Dialog = new CustomCircularLoadingDialog(this.mContext); 
     this.utility = new HttpUtility(this.UrlString, mContext); 
     Utilities.setCurrentHitURL(mContext, UrlString); 
    } 

    public void setOnCompletedListener(IHttpRequestCompletedListener listener) { 
     this.listener = listener; 
    } 

    public void setWaitMessage(String msgText) { 
     if (!msgText.equals("")) 
      msgText = "\n" + msgText; 
     this._messageText = _messageText + msgText; 
    } 

    public void addPostItem(NameValuePair nameValuePair) { 
     this.utility.addNameValuePairs(nameValuePair); 
    } 

    public void addGetHeader(String headerData) { 
     this.utility.addGetHeader(headerData); 
    } 

    public void addPostHeader(String headerData) { 
     this.utility.addPostHeader(headerData); 
    } 

    public void setTypePost() { 
     this.type = "post"; 
    } 

    @Override 
    protected void onPreExecute() { 
     if (_showProgressDialog) { 
      Dialog.setMessage(this._messageText); 
      Dialog.setCancelable(false); 
      Dialog.setCanceledOnTouchOutside(false); 
      this.Dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT)); 
      Dialog.show(); 
     } 
    } 

    @Override 
    protected String doInBackground(Void... params) { 

     if (!Utilities.isNetworkAvailable(mContext)) 
      return "No network available"; 
     try { 
      if (this.type.equals("get")) 
       return utility.doGetRequest(); 
      else 
       return utility.doPostRequest(); 
     } catch (MediCorporateException tex) { 

      if (listener != null) { 
       if (isActivity) { 
        ((Activity) mContext).runOnUiThread(new Runnable() { 
         @Override 
         public void run() { 
          listener.OnHttpRequestError(); 
         } 
        }); 
       } else { 
        ((GcmIntentService) mContext).runOnUIThread(new Runnable() { 
         @Override 
         public void run() { 
          listener.OnHttpRequestError(); 
         } 
        }); 
       } 
      } 
      Utilities.callCrashReport(mContext, tex); 
     } 
     Log.i("Exit ", "doInBackground"); 

     return ""; 
    } 

    @Override 
    protected void onPostExecute(String Result) { 
     if (_showProgressDialog) 
      this.Dialog.dismiss(); 
     Log.i("Came in", "onPostExecute"); 
     if (this.listener != null) { 
      if (!Utilities.isNullOrEmpty(Result)) 
       listener.OnHttpRequestCompleted(Result); 
      else { 
       logoutUser(); 
       listener.OnHttpRequestError(); 
      } 
     } 
     Log.i("Exit ", "onPostExecute"); 
    } 

} 

はHttpUtilityクラスの要求&応答を処理するための機能です。

public String doGetRequest() throws MediCorporateException { 

     String resp = ""; 
     int responseCode = 0; 
     try { 
      if (header != null) { 
       if (header.length() > 0) { 
        httpURLConnection.setRequestMethod("GET"); 
        httpURLConnection.setRequestProperty("Authorization", header); 
       } 
      } 
      responseCode = httpURLConnection.getResponseCode(); 
      InputStream inputStream = new BufferedInputStream(this.httpURLConnection.getInputStream()); 
      resp = readResponse(inputStream); 
      Log.v("Resp", "" + responseCode + " --- " + resp); 
      inputStream.close(); 
     } catch (IOException ioExc) { 
      FileLog.e(getClass().getName(), ioExc); 
      resp = ioExc.getMessage(); 
      throw new MediCorporateException("Http IO Exception..."); 
     } catch (Exception ex) { 
      FileLog.e(getClass().getName(), ex); 
      throw new MediCorporateException("Http Error..."); 
     } finally { 

      this.httpURLConnection.disconnect(); 
      if (responseCode == 401) 
       return "" + responseCode; 
      if (responseCode != 200) 
       return null; 
     } 

     return resp; 
    } 

)(DoPostRequest、次のとおりです。

public String doGetRequest() throws MediCorporateException { 

     String resp = ""; 
     int responseCode = 0; 
     try { 
      if (header != null) { 
       if (header.length() > 0) { 
        httpURLConnection.setRequestMethod("GET"); 
        httpURLConnection.setRequestProperty("Authorization", header); 
       } 
      } 
      responseCode = httpURLConnection.getResponseCode(); 
      InputStream inputStream = new BufferedInputStream(this.httpURLConnection.getInputStream()); 
      resp = readResponse(inputStream); 
      Log.v("Resp", "" + responseCode + " --- " + resp); 
      inputStream.close(); 
     } catch (IOException ioExc) { 
      FileLog.e(getClass().getName(), ioExc); 
      resp = ioExc.getMessage(); 
      throw new MediCorporateException("Http IO Exception..."); 
     } catch (Exception ex) { 
      FileLog.e(getClass().getName(), ex); 
      throw new MediCorporateException("Http Error..."); 
     } finally { 

      this.httpURLConnection.disconnect(); 
      if (responseCode == 401) 
       return "" + responseCode; 
      if (responseCode != 200) 
       return null; 
     } 

     return resp; 
    } 

&書き込み応答関数を読んで、次の。

private void writePostMethod(OutputStream outputStream) throws Exception { 
     if (this.nameValuePairs.size() <= 0) 
      throw new Exception("Cannot use post method with no values to post"); 
     String postStr = ""; 
     for (NameValuePair item : this.nameValuePairs) 
      postStr += URLEncoder.encode(item.getName(), "UTF-8") + "=" + URLEncoder.encode(item.getValue(), "UTF-8") + "&"; 
     postStr = postStr.substring(0, postStr.length() - 1); 
     Log.v("Post Values", postStr); 
     BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8")); 
     writer.write(postStr); 
     writer.flush(); 
     writer.close(); 
    } 

    private String readResponse(InputStream inputStream) throws IOException { 
     int i; 
     ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
     while ((i = inputStream.read()) != -1) 
      outputStream.write(i); 

     byte[] responseBytes = outputStream.toByteArray(); 
     ByteArrayInputStream bais = new ByteArrayInputStream(responseBytes); 
     InputStreamReader reader; 
     if (!this._urlString.contains("token")) { 
      GZIPInputStream gzis = new GZIPInputStream(bais); 
      reader = new InputStreamReader(gzis); 
      gzis.close(); 
     } else 
      reader = new InputStreamReader(bais); 

     BufferedReader in = new BufferedReader(reader); 
     StringBuilder total = new StringBuilder(); 
     String readed; 
     while ((readed = in.readLine()) != null) { 
      total.append(readed); 
      bais.close(); 
     } 
     in.close(); 
     reader.close(); 
     inputStream.close(); 
     outputStream.close(); 
     return total.toString(); 
    } 
+0

スタックトレースはどこですか? – Michael

+0

私は自分の質問を編集しました。 –

+0

各スレッドはメモリ消費量の面で多くのコストがかかります。 OOMはネイティブメソッドで発生しますが、アプリケーションがヒープを使い果たしたときには、OOMの実際の点は無関係です。したがって、私は** [tag:jni] **タグを削除しました。 –

答えて

1

ストリームからデータを読み取っているときに入出力ストリームまたはバッファを正しく閉じていないようです。 InputStreamからの応答を読み取るには、以下のスニペットを試してください。

org.apache.commons.ioのIOUtilsを使用してください。することはできdownload jar

private String readResponse(InputStream inputStream) throws IOException { 
    if (!this._urlString.contains("token")) { 
     GZIPInputStream gzipIn = new GZIPInputStream(inputStream); 
     return IOUtils.toString(gzipIn);  
    }else { 
     if (inputStream != null) { 
      BufferedReader reader = new BufferedReader(
        new InputStreamReader(inputStream)); 
      StringBuilder sb = new StringBuilder(); 

      String line = null; 
      try { 
       while ((line = reader.readLine()) != null) { 
        sb.append(line + "\n"); 
       } 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } finally { 
       try { 
        inputStream.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
      return sb.toString(); 
     } 
    } 
    return null; 
} 

OOMのほとんどは、アプリケーションに割り当てられたヒープサイズに起因しているけど。マニフェストファイルにタグを追加することでヒープサイズを大きくすることができます。

<application 
    android:name="ApplicationLoader" 
    android:largeHeap="true"> 

あなたのレポを通過した後、すべての例外について、ログとクラッシュレポートをFireBaseに送信していることがわかりました。それはOOMにつながるあなたのスレッドプールのメモリ不足につながります。クラッシュやイベントをバッチで送信してください。

0

各スレッドのメモリ消費量は非常に多くなります。

AsyncTaskはスレッドプールを管理しますが、ネットワークアクティビティ用に最適化されていません。実際には、同じサーバーへのHTTPリクエストが多い場合は、同じスレッドにそれらを保持し、可能な限り永続的な接続を再利用するために、メモリ消費と全体的なパフォーマンスの面で優れています。 AsyncTaskはこのような問題を考慮しません。

非同期要求を提供する信頼できるHTTPクライアントがかなりあります。 OkHttpまたはvolley、またはAndroid Asynchronous Http Client、J.Smith、またはGitHubの他の多くのプロジェクト

独自のHTTPクライアントを作成することはできますが、少なくともこの分野で他の人が何をしているのか、以前に何が間違っていたのかを勉強することは賢明でしょう。

関連する問題