Android and Java: Reduce memory usage on a service

2020-03-30 06:00发布

I have an Android Service which updates a notification every second using this Thread (comments are not really relevant):

thread = new Thread() {
    @Override
    public void run() {
        // Preparando la notificación de Swap
        NotificationCompat.Builder notificationSwap =
                new NotificationCompat.Builder(context)
                        .setSmallIcon(android.R.drawable.ic_dialog_info)
                        .setContentTitle("Notificator:");
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        int notificationSwapId = 1; // TODO: Asignar un ID que no sea "Magic number"

        while (!stop) {
            String swapInfo = null;

            try{ // TODO: free devuelve siempre 4 líneas?
                Process free = Runtime.getRuntime().exec("free");
                BufferedReader freeOut =
                        new BufferedReader(
                                new InputStreamReader(new DataInputStream(free.getInputStream())));
                free.waitFor();
                freeOut.readLine();
                freeOut.readLine();
                freeOut.readLine();
                swapInfo = freeOut.readLine();
            }catch(Exception e){
                Log.e("ERROR", e.toString()); // TODO: Mejorar esto
            }
            Scanner scanner = new Scanner(swapInfo); // TODO: Mejorar esto
            String swapInfo2 = null;
            if (scanner.hasNext()) {
                scanner.skip("Swap:");
            }
            if (scanner.hasNextInt()) {
                /*swapInfo2 = "Total: " + */scanner.nextInt();
            }
            if (scanner.hasNextInt()) {
                swapInfo2 = "Usado: " + scanner.nextInt();
            }
            if (scanner.hasNextInt()) {
                swapInfo2 += "\nLibre: " + scanner.nextInt();
            }

            // Notificando
            notificationSwap.setContentText(swapInfo2);
            notificationManager.notify(notificationSwapId, notificationSwap.build());

            // Intentando liberar memoria
            //System.gc();

            try {
                Thread.sleep(new Integer(PreferenceManager.getDefaultSharedPreferences(context).getString("frecuency", "60000"))); // TODO: Mejorar esto
            } catch (InterruptedException e){
                Log.d("Notificator (Service)", "Deteniendo el hilo durante la espera"); // TODO: Mejorar esto
                // TODO: ¿Qué pasa si el hilo es interrumpido fuera del try/catch? Si pilla la interrupción no hace falta la variable stop
            }
        }
    }
};

The problem is that it uses about 20MB of memory but if I uncomment the "//System.gc();" line that number lowers to about 3/4MB, thats A LOT of garbage. But running the whole Garbage Collector every loop does not seem very efficient to me, and CPU usage goes higher.

Thats why I don't like garbage collectors, on a c++ loop just by using auto variables I wouldn't have this problem, but I think this could be better done since I'm not really used neither to Java nor Android.

So, my main question is, how can I lower memory usage in a more eficient way? I also would apreciate better ways to uptate a notification on Android but what I really need is to prevent this kind of code from using so many memory.

UPDATE:

Answers are suggesting that I should close the Stream, the Scanner, etc, I'm not really sure whether this is necesary or not (closing the stream and the scanner does not solve the problem) but I think that's not the problem since they are being succesfully deleted anyway.

The problem is that they pile up before being deleted and I want to delete them just before the thread sleeps instead of waiting to the garbage collector, and since that cannot be done in Java as far as I know, I need a more "garbage collector friendly" aproach.

2条回答
Viruses.
2楼-- · 2020-03-30 06:40

how can I lower memory usage in a more eficient way?

The big thing would be to get rid of all of this process-forking nonsense and replace it with a simple call to getMemoryInfo(). Or, use JNI to call some C APIs to get your memory information. Forking a process every second is exceedingly wasteful on a mobile device. Besides, you have no way of knowing if free exists on every device, as on-device command-line binaries are not part of the Android SDK and are not guaranteed to be consistent.

Secondarily, use StringBuilder or String.format() rather than string concatenation to build up your Notification text.

查看更多
男人必须洒脱
3楼-- · 2020-03-30 06:41

In finally block you can do the following thing

 finally {
try {
    freeOut.close();
} catch (IOException e) {
    e.printStackTrace();
}
查看更多
登录 后发表回答