簡體   English   中英

Android:打開文件太多錯誤

[英]Android: Too many open files error

我有以下每 3 秒運行一次的操作。
基本上,它每 3 秒從服務器下載一個文件並將其保存到本地文件中。
下面的代碼完成了一段時間的工作。

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

    @Override
    protected String doInBackground(String... params) {
        downloadCommandFile( eventUrl);
        return null;
    }


}

private void downloadCommandFile(String dlUrl){
    int count;
    try {
        URL url = new URL( dlUrl );
        NetUtils.trustAllHosts();
        HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
        con.setDoInput(true);
        con.setDoOutput(true);
        con.connect();
        int fileSize = con.getContentLength();
        Log.d(TAG, "Download file size = " + fileSize );
        InputStream is = url.openStream();
        String dir = Environment.getExternalStorageDirectory() + Utils.DL_DIRECTORY;
        File file = new File( dir );
        if( !file.exists() ){
            file.mkdir();
        }

        FileOutputStream fos = new FileOutputStream(file + Utils.DL_FILE);
        byte data[] = new byte[1024];
        long total = 0;

        while( (count = is.read(data)) != -1 ){
            total += count;
            fos.write(data, 0, count);
        }

        is.close();
        fos.close();
        con.disconnect(); // close connection


    } catch (Exception e) {
        Log.e(TAG, "DOWNLOAD ERROR = " + e.toString() );
    }

}

一切正常,但如果我讓它運行 5 到 10 分鍾,我會收到以下錯誤。

06-04 19:40:40.872: E/NativeCrypto(6320): AppData::create pipe(2) 失敗:打開的文件太多 06-04 19:40:40.892: E/NativeCrypto(6320): AppData::create管道(2)失敗:打開的文件太多 06-04 19:40:40.892: E/EventService(6320): DOWNLOAD ERROR = javax.net.ssl.SSLException: 無法創建應用程序數據

最近兩天我一直在做一些研究。
有人建議他們打開許多連接,比如這個https://stackoverflow.com/a/13990490/1503155但我仍然不知道是什么問題。
任何可能導致問題的想法?
提前致謝。

我認為您會收到此錯誤消息是因為您同時打開了太多文件,這意味着您同時運行了太多異步任務(每個異步任務都打開了一個文件),如果您說您運行了一個每3秒更新一次。

您應該嘗試使用線程池執行程序來限制同時運行的異步任務的數量。

嘗試使用OkHttp代替。

您的問題不是線程過多,盡管這是導致問題浮出水面的原因。

就像注釋中提到的@stdout一樣,除非您另外指定,否則AsyncTask已經在所有AsyncTask中共享的線程池中運行。 這里的問題是,文件描述符未及時正確關閉。

問題是您的文件描述符關閉得不夠快。

我為此花費了數小時,數天,數周的時間,在做所有您想設置較小的讀取/連接超時並使用finally塊關閉連接,輸入流,輸出流等的工作。但是我們從未找到可行的解決方案。 HttpsUrlConnection似乎在某種程度上存在缺陷。

因此,我們嘗試使用OkHttp替代HttpsUrlConnectionHttpsUrlConnection 它開箱即用。

因此,如果您對此感到掙扎,並且很難解決它,建議您也嘗試使用OkHttp。

以下是基本知識:

添加Maven依賴項后,您可以執行以下操作來下載文件:

OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

OutputStream output = null;

try {
  Request request   = new Request.Builder().url( download_url ).build();
  Response response = okHttpClient.newCall( request ).execute();

  if ( !response.isSuccessful() ) {
    throw new FileNotFoundException();
  }

  output = new FileOutputStream( output_path );

  output.write( response.body().bytes() );
}
finally {
  // Ensure streams are closed, even if there's an exception.
  if ( output != null ) output.flush();
  if ( output != null ) output.close();
}

切換到OkHttp會立即解決我們泄漏的文件描述符問題,因此即使您被卡住了也值得嘗試,即使是以增加另一個庫依賴項為代價。

我不得不一次下載數百個文件並遇到錯誤。

您可以使用以下命令檢查打開的描述符:

adb shell ps

在列表中找到您的應用程序 PID 並使用另一個命令:

adb shell run-as YOUR_PACKAGE_NAME ls -l  /proc/YOUR_PID/fd

我在通常的發布中看到大約 150 個打開的描述符。 下載文件時有 700 多個。 它們的數量僅在幾分鍾后才會減少,看起來 Android 會在后台釋放它們,而不是在您可以close流時。

唯一可行的解​​決方案是使用自定義 ThreadPool 來限制並發性。 這是 Kotlin 代碼:

private val downloadDispatcher = Executors.newFixedThreadPool(8).asCoroutineDispatcher()

private suspend fun downloadFile(sourceUrl: String, destPath: String, progressBlock: suspend (Long) -> Unit) = withContext(downloadDispatcher) {
    val url = URL(sourceUrl)
    url.openConnection().apply { connect() }
    url.openStream().use { input ->
        FileOutputStream(File(destPath)).use { output ->
            val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
            var bytesRead = input.read(buffer)
            var bytesCopied = 0L
            while (bytesRead >= 0) {
                if (!coroutineContext.isActive) break
                output.write(buffer, 0, bytesRead)
                bytesCopied += bytesRead
                progressBlock(bytesCopied)
                bytesRead = input.read(buffer)
            }
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM