【问题标题】:Android MultiThread SpeedTest have performances problemsAndroid MultiThread SpeedTest 有性能问题
【发布时间】:2014-02-12 13:23:24
【问题描述】:

我最近开始做一个速度测试应用程序。 方法很简单:

我实例化多个线程都下载同一个不可压缩文件,然后我计算平均下载速度。

但我认为我遇到了一些性能问题。当我用多个线程开始测试时,我在 logCat 中看到很多 GC_CONCURRENT freedWAIT_FOR_CONCURRENT_GC。 我不明白这是从哪里来的。

通常这些问题似乎出现在某些情况下,例如实例化太多对象或巨大对象,但我不认为这里是这种情况......

这是我的代码(简化 - 没有速度计算):

public class SpeedTest extends Activity{

    private final int NB_THREADS = 2;
    private long bytesIn;
    private long downloadTime;

    private List<Downloader> downloaders = new ArrayList<Downloader>();

    @Override
    protected void onCreate(Bundle savedInstanceState){

        super.onCreate(savedInstanceState);
        setContentView(R.layout.speed_test);

        bytesIn = 0;

        for (int i = 0; i < NB_THREADS; i++){
            downloaders.add(new Downloader());
            downloaders.get(i).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, i);
        }
    }

    private synchronized void addBytes(){ bytesIn++; }

    private class Downloader extends AsyncTask<Integer, Void, Void>{

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

            Log.d("eduine", "Downloader " + params[0] + " started");

            try{

                InputStream stream = new URL("http://test-de-vitesse.ariase.com/ariasetool/1mb_random.bin").openConnection().getInputStream();

                while((stream.skip(1)) != 0){
                    addBytes();
                }

                stream.close();

            }catch (MalformedURLException e){
                e.printStackTrace();
                Log.e("eduine", "malformed url : " + e.getMessage());
            }catch (IOException e){
                e.printStackTrace();
                Log.e("eduine", "io error : " + e.getMessage());
            }

            Log.d("eduine", "Downloader " + params[0] + " terminated");

            return null;
        }
    }
}

所以我想知道是否有人已经遇到过这个问题,或者知道为什么会出现这些性能问题,因为它会扭曲速度计算。

提前致谢!


编辑:忘记发布 logCat,抱歉。

02-12 14:18:40.945: D/eduine(15637): Downloader 0 started
02-12 14:18:40.955: D/eduine(15637): Downloader 1 started
02-12 14:18:41.355: D/dalvikvm(15637): GC_CONCURRENT freed 3102K, 33% free 7552K/11240K, paused 3ms+3ms, total 20ms
02-12 14:18:41.395: D/dalvikvm(15637): GC_CONCURRENT freed 1564K, 33% free 7533K/11240K, paused 3ms+3ms, total 18ms
02-12 14:18:41.465: D/dalvikvm(15637): GC_CONCURRENT freed 1657K, 33% free 7537K/11240K, paused 2ms+7ms, total 20ms
02-12 14:18:41.465: D/dalvikvm(15637): WAIT_FOR_CONCURRENT_GC blocked 8ms
02-12 14:18:41.485: D/dalvikvm(15637): GC_CONCURRENT freed 1657K, 33% free 7541K/11240K, paused 2ms+3ms, total 17ms
02-12 14:18:41.485: D/dalvikvm(15637): WAIT_FOR_CONCURRENT_GC blocked 10ms
02-12 14:18:41.505: D/dalvikvm(15637): GC_CONCURRENT freed 1669K, 33% free 7533K/11240K, paused 3ms+1ms, total 17ms
02-12 14:18:41.505: D/dalvikvm(15637): WAIT_FOR_CONCURRENT_GC blocked 10ms
02-12 14:18:41.525: D/dalvikvm(15637): GC_CONCURRENT freed 1609K, 33% free 7537K/11240K, paused 3ms+3ms, total 16ms
02-12 14:18:41.545: D/dalvikvm(15637): GC_CONCURRENT freed 1669K, 34% free 7529K/11240K, paused 3ms+2ms, total 16ms
02-12 14:18:41.545: D/dalvikvm(15637): WAIT_FOR_CONCURRENT_GC blocked 13ms

等等等等……直到

02-12 14:21:14.795: D/dalvikvm(16164): GC_CONCURRENT freed 1537K, 33% free 7533K/11240K, paused 3ms+2ms, total 16ms
02-12 14:21:14.815: D/dalvikvm(16164): GC_CONCURRENT freed 1537K, 33% free 7533K/11240K, paused 2ms+2ms, total 15ms
02-12 14:21:14.835: D/dalvikvm(16164): GC_CONCURRENT freed 1537K, 33% free 7533K/11240K, paused 2ms+3ms, total 16ms
02-12 14:21:14.845: D/eduine(16164): Downloader 0 terminated at 1392211274859
02-12 14:21:14.855: D/dalvikvm(16164): GC_CONCURRENT freed 1545K, 34% free 7529K/11240K, paused 3ms+3ms, total 17ms
02-12 14:21:14.915: D/eduine(16164): Downloader 1 terminated at 1392211274925

编辑:使用 ThreadPool 时同样的问题,代码如下。

public class SpeedTest extends Activity{

    private final int NB_OF_THREADS = 8;
    private long bytesIn;
    private long start;

    ExecutorService executorService = new ThreadPoolExecutor(NB_OF_THREADS, NB_OF_THREADS, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(NB_OF_THREADS, true), new ThreadPoolExecutor.CallerRunsPolicy());

    @Override
    protected void onCreate(Bundle savedInstanceState){

        super.onCreate(savedInstanceState);
        setContentView(R.layout.speed_test);

        bytesIn = 0;
        start = System.currentTimeMillis();
        for (int i = 0; i < NB_OF_THREADS; i++) executorService.submit(new Downloader(i));
    }

    private synchronized void addByte(){ bytesIn++; }

    private class Downloader implements Runnable{

        private int id;
        private InputStream stream;
        private long downloadTime;

        public Downloader(int _id){ id = _id; }

        @Override
        public void run(){

            Log.d("eduine", "Downloader " + id + " started at " + System.currentTimeMillis());

            try{

                HttpURLConnection connexion = (HttpURLConnection) new URL("http://test-de-vitesse.ariase.com/ariasetool/1mb_random.bin").openConnection();
                connexion.setUseCaches(false);
                stream = connexion.getInputStream();

                while((stream.skip(1)) != 0) addByte();

                stream.close();

                downloadTime = (System.currentTimeMillis() - start);
                downloadTime = downloadTime == 0 ? 1 : downloadTime;

            }catch (MalformedURLException e){
                e.printStackTrace();
                Log.e("eduine", "malformed url : " + e.getMessage());
            }catch (IOException e){
                e.printStackTrace();
                Log.e("eduine", "io error : " + e.getMessage());
            }

            Log.d("eduine", "Downloader " + id + " terminated at " + System.currentTimeMillis());
        }
    }
}

【问题讨论】:

    标签: java android multithreading garbage-collection


    【解决方案1】:

    线程对象本身会为其堆栈消耗大量内存。要从实例化/释放线程中清除测试,请不要使用 AsyncTask(它会创建线程),而是预先创建一个固定的线程池,开始测试,等待它结束,然后才关闭线程池。

    【讨论】:

    • 即使使用 ThreadPool 我也有同样的问题。如果您想查看,请在上面发布我的代码。
    • 看起来大量内存分配删除发生在其他地方。制作最小的程序并在 Android 上运行。制作更小的程序并使用 gc log 在桌面上运行。
    • 我终于找到了错误,实际上存在分配问题,我在循环中重新分配了一个字节[],因此这种方式使用了大量内存。现在解决了,谢谢。
    猜你喜欢
    • 2021-05-20
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    • 2012-01-02
    相关资源
    最近更新 更多