Resumen de pérdidas de memoria de Android y consejos de optimización del rendimiento

       Cuando desarrollamos aplicaciones para Android, la optimización del rendimiento es un aspecto muy importante. Por un lado, la optimización puede mejorar la velocidad de respuesta de la aplicación, reducir la tasa de retraso y mejorar la fluidez de la aplicación, mejorando así la experiencia del usuario; por otro lado, la optimización también puede reducir el uso de recursos de la aplicación, mejorar la estabilidad y seguridad de la aplicación, y reduce el costo de la aplicación y la probabilidad de ser eliminada, mejorando así la satisfacción y retención del usuario.

      Sin embargo, para muchos desarrolladores, la optimización del rendimiento de Android suele ser una cuestión difícil. Dado que existen muchos tipos de dispositivos Android con diferentes configuraciones de hardware, los métodos y estrategias de optimización también son diferentes. Al mismo tiempo, el ciclo de desarrollo de las aplicaciones de Android es largo y, a menudo, requiere iteraciones y actualizaciones continuas, por lo que la optimización también debe continuar y optimizarse.

        Aprender los conocimientos y habilidades de optimización del rendimiento de Android es una de las habilidades esenciales para todo desarrollador de Android. Al dominar los principios y métodos básicos de optimización del rendimiento de Android, podemos tener una comprensión más profunda del mecanismo de trabajo de los dispositivos Android y comprender los cuellos de botella en el rendimiento de las aplicaciones, a fin de adoptar estrategias y medidas de optimización efectivas para mejorar el rendimiento y la estabilidad de las aplicaciones y mejorar. satisfacción del usuario y tasas de retención.


       Este artículo presenta los principios básicos, las estrategias de optimización y las técnicas prácticas de optimización del rendimiento de Android para ayudar a los desarrolladores a comprender mejor el principio de funcionamiento de los dispositivos Android y dominar los métodos y técnicas básicos de optimización del rendimiento de Android, mejorando así el rendimiento y la estabilidad de las aplicaciones y proporcionando a los usuarios. con Proporciona una experiencia más sedosa.

Existe una amplia gama de problemas de optimización del rendimiento de Android. Estos son algunos de los más comunes:

  1. Pérdidas de memoria: las pérdidas de memoria ocurren cuando una aplicación administra incorrectamente la memoria, lo que provoca un uso excesivo de la misma o incluso provoca que la aplicación falle.

  2. Optimización del diseño: el diseño es uno de los cuellos de botella de rendimiento más comunes en las aplicaciones, porque un diseño demasiado complejo puede hacer que la aplicación responda lentamente o se congele.

  3. Optimización de imágenes: las imágenes son uno de los recursos que consumen más memoria en una aplicación, por lo que deben usarse con precaución y comprimirse y almacenarse en caché adecuadamente para garantizar el rendimiento de la aplicación.

  4. Optimización de solicitudes de red: las solicitudes de red pueden consumir mucho tiempo y recursos en una aplicación, por lo que deben optimizarse para reducir la cantidad de solicitudes y aumentar la velocidad de respuesta.

  5. Optimización de la base de datos: cuando una aplicación requiere un gran acceso a la base de datos, puede causar problemas de rendimiento. El rendimiento de la aplicación se puede mejorar optimizando el diseño de la base de datos y utilizando el almacenamiento en caché de la base de datos adecuado.

  6. Optimización de subprocesos múltiples: los subprocesos múltiples pueden mejorar el rendimiento de la aplicación, pero si se usan incorrectamente, pueden provocar interbloqueos, contención de subprocesos y otros problemas.

  7. Optimización de la memoria: la memoria es uno de los factores importantes en el rendimiento de la aplicación. Puede mejorar el rendimiento de la aplicación liberando rápidamente la memoria que ya no es necesaria y evitando asignaciones de memoria innecesarias.

  8. Optimización de código: la optimización de las estructuras y algoritmos del código puede mejorar el rendimiento de la aplicación. Por ejemplo, utilice estructuras de datos y algoritmos más rápidos y eficientes para mejorar la capacidad de respuesta de las aplicaciones.

  9. Optimización de la seguridad: los problemas de seguridad también pueden afectar negativamente el rendimiento de su aplicación. Puede mejorar la seguridad y el rendimiento de las aplicaciones evitando prácticas de codificación inseguras y utilizando cifrado para proteger sus datos.

La optimización del rendimiento de Android se reduce a problemas de memoria, y la optimización a nivel de memoria no son solo los elementos de optimización convencionales descritos en la descripción, sino que también pueden optimizar aún más la cantidad de lecturas y escrituras del disco, la sincronización de datos de la página del disco, etc.

1. Pérdida de memoria

Una pérdida de memoria se refiere a la incapacidad de una aplicación para liberar correctamente los recursos de memoria que ya no se utilizan durante la operación, lo que resulta en un aumento continuo en el uso de la memoria y, eventualmente, hace que la aplicación falle o se ejecute lentamente.

El principio de pérdida de memoria.

El principio de pérdida de memoria de Android significa que cuando una aplicación usa memoria, debido a problemas o errores de programación, no puede liberar la memoria que ya no se usa, lo que finalmente conduce a una memoria insuficiente en el sistema, afectando la estabilidad y el rendimiento del sistema. .


A continuación se muestran algunas causas comunes que pueden provocar pérdidas de memoria en Android:

Referencia de objeto no publicada

Cuando se crean objetos, si no se liberan correctamente, estos objetos ocuparán memoria hasta que se cierre la aplicación. Por ejemplo, cuando se destruye una actividad, si todavía contiene referencias a otros objetos, el recolector de basura no puede reciclar estos objetos, lo que provoca una pérdida de memoria.

Si hay una pérdida de memoria, se hará referencia a los objetos en estas memorias y el mecanismo de recolección de basura no podrá reciclarlos. En este momento, necesitamos usar GCRoot para identificar los objetos y las referencias con pérdida de memoria.

GCRoot es el nodo raíz en el mecanismo de recolección de basura. El nodo raíz incluye la pila de la máquina virtual, la pila de métodos locales, las referencias de atributos estáticos de clase en el área del método, los subprocesos activos, etc. La basura considera estos objetos como "objetos vivos". mecanismo de recolección y no será reciclado.


Cuando se ejecuta el mecanismo de recolección de basura, comenzará desde GCRoot, atravesará todas las referencias de objetos y marcará todos los objetos vivos. Los objetos no marcados son objetos basura y se reciclarán.


Cuando hay una pérdida de memoria, el mecanismo de recolección de basura no puede reciclar algunos objetos que ya no se usan. Estos objetos todavía están referenciados, formando algunas cadenas de referencia desde GCRoot hasta los objetos con pérdida de memoria. Estos objetos no se reciclarán, lo que provocará pérdidas de memoria.


Al encontrar la cadena de referencia entre el objeto de pérdida de memoria y GCRoot, se puede localizar la fuente de la pérdida de memoria y resolver el problema de pérdida de memoria. LeakCancry se implementa a través de este mecanismo. Algunos GCRoots comunes incluyen:

  • Objeto referenciado en la pila de la máquina virtual (Variable local).

  • El objeto al que hace referencia la propiedad estática (variable estática) en el área de método.

  • El objeto al que hace referencia JNI.

  • Objeto al que hace referencia el hilo de Java (Thread).

  • Objetos retenidos por bloqueos sincronizados en Java.

Pérdida de memoria causada por una clase interna anónima

Las clases internas anónimas generalmente contienen referencias a clases externas. Si el ciclo de vida de la clase externa es más largo que el de la clase interna anónima (corrección, el uso del ciclo de vida no es apropiado aquí. Cuando se destruye la clase externa, la clase interna La clase no se destruirá automáticamente. , debido a que la clase interna no es una variable miembro de la clase externa, son solo objetos creados dentro del alcance de la clase externa, por lo que el tiempo de destrucción de la clase interna y el tiempo de destrucción de la clase externa Las clases son diferentes, por lo que dependerá de si el objeto correspondiente existe (la referencia mantenida) hará que la clase externa no se pueda reciclar, lo que provocará una pérdida de memoria.

Las variables estáticas contienen referencias a Actividad o Contexto

Si una variable estática contiene una referencia a una actividad o contexto, el recolector de basura no puede reciclar estas actividades o contextos, lo que genera una pérdida de memoria.

Objeto de cursor, secuencia o mapa de bits no cerrado

Si el programa no cierra correctamente los objetos Cursor, Stream o Bitmap cuando utiliza estos objetos, estos objetos seguirán ocupando memoria, lo que provocará pérdidas de memoria.

Recursos no liberados

Si el programa no libera correctamente los recursos del sistema cuando los usa, como no cerrar las conexiones de la base de datos, no liberar los recursos de audio, etc., estos recursos seguirán ocupando memoria, lo que provocará pérdidas de memoria.

Pérdidas de memoria comunes

Pérdidas de memoria causadas por referencias estáticas

Cuando un objeto está retenido por una variable estática, incluso si el objeto ya no se usa, el recolector de basura no lo reciclará, lo que provocará una pérdida de memoria.

public class MySingleton {
    private static MySingleton instance;
    private Context context;

    private MySingleton(Context context) {
        this.context = context;
    }

    public static MySingleton getInstance(Context context) {
        if (instance == null) {
            instance = new MySingleton(context);
        }
        return instance;
    }
}

En el código anterior, MySingleton contiene una referencia a un objeto Context y MySingleton es una variable estática, lo que significa que incluso si el objeto ya no se usa, el recolector de basura no lo reciclará.

Nota: Si necesita utilizar variables estáticas, tenga cuidado de establecerlas en nulas cuando no las necesite para que la memoria pueda liberarse a tiempo.

Pérdida de memoria causada por una clase interna anónima

La clase interna anónima contendrá implícitamente una referencia a la clase externa. Si se mantiene la clase interna anónima, la clase externa no será recolectada como basura.

public class MyActivity extends Activity {
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        button = new Button(this);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // do something
            }
        });
        setContentView(button);
    }
}

La clase interna anónima OnClickListener contiene una referencia a la clase externa MyActivity. Si el botón no se borra antes de destruir MyActivity, MyActivity no se recolectará como basura. (El botón puede considerarse como un objeto definido por usted mismo aquí. La solución general es configurar el objeto del botón como vacío)

Nota: Cuando se destruye la Actividad, todos los objetos que contengan referencias a la Actividad deben establecerse en nulo.

Pérdida de memoria causada por Handler

Handler es un mecanismo de comunicación de subprocesos comúnmente utilizado en aplicaciones de Android. Si Handler se usa incorrectamente, provocará pérdidas de memoria.

public class MyActivity extends Activity {
    private static final int MSG_WHAT = 1;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_WHAT:
                    // do something
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler.sendEmptyMessageDelayed(MSG_WHAT, 1000 * 60 * 5);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 在Activity销毁时,应该将Handler的消息队列清空,以避免内存泄漏。
        mHandler.removeCallbacksAndMessages(null);
        }
}

El Controlador contiene una referencia a la Actividad. Si hay mensajes sin procesar en la cola de mensajes del Controlador antes de que se destruya la Actividad, la Actividad no se recolectará como basura.


Nota: Cuando se destruye la Actividad, la cola de mensajes del Controlador debe borrarse para evitar pérdidas de memoria.

Pérdida de memoria causada por un objeto Bitmap

Cuando se crea un objeto Bitmap, ocupará una gran cantidad de memoria y, si no se libera a tiempo, provocará una pérdida de memoria.

public class MyActivity extends Activity {
private Bitmap mBitmap;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 加载一张大图
    mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.big_image);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    // 释放Bitmap对象
    mBitmap.recycle();
    mBitmap = null;
}
}

Cuando se destruye la Actividad, el objeto Bitmap mBitmap debe liberarse a tiempo; de lo contrario, provocará una pérdida de memoria.

Nota: Cuando se utiliza una gran cantidad de objetos de mapa de bits, los objetos no utilizados deben reciclarse a tiempo para evitar pérdidas de memoria. Además, puede considerar el uso de bibliotecas de carga de imágenes para administrar objetos de mapa de bits, como Glide, Picasso, etc.

Pérdidas de memoria causadas por recursos que no se cierran

Al utilizar algunos recursos del sistema, como archivos, bases de datos, etc., si no se cierran a tiempo, pueden producirse pérdidas de memoria. Por ejemplo:

public void readFile(String filePath) throws IOException {
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(filePath);
        // 读取文件...
    } finally {
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

En el código anterior, si el objeto FileInputStream no se cierra a tiempo después de leer el archivo, puede provocar una pérdida de memoria.


Nota: Cuando se utilizan algunos recursos del sistema, como archivos, bases de datos, etc., los objetos relevantes deben cerrarse a tiempo para evitar pérdidas de memoria.


Para evitar pérdidas de memoria, siempre debe prestar atención al escribir código, limpiar rápidamente los objetos que ya no se utilizan y asegurarse de que los recursos de memoria se liberen de manera oportuna. Al mismo tiempo, puede utilizar algunas herramientas para detectar problemas de pérdida de memoria, como Android Profiler, LeakCanary, etc.

Pérdida de memoria de WebView

Cuando se utiliza WebView, si no se publica a tiempo, puede provocar una pérdida de memoria.

public class MyActivity extends Activity {
    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = findViewById(R.id.webview);
        mWebView.loadUrl("https://www.example.com");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 释放WebView对象
        if (mWebView != null) {
            mWebView.stopLoading();
            mWebView.clearHistory();
            mWebView.clearCache(true);
            mWebView.loadUrl("about:blank");
            mWebView.onPause();
            mWebView.removeAllViews();
            mWebView.destroy();
            mWebView = null;
        }
    }
}

En el código anterior, cuando se destruye la Actividad, el objeto WebView debe liberarse a tiempo; de lo contrario, puede provocar una pérdida de memoria.

Nota: Cuando utilice WebView, debe liberar el objeto WebView a tiempo. Puede llamar al método de destrucción de WebView cuando se destruye la actividad. Al mismo tiempo, también debe borrar el historial, el caché, etc. de WebView para garantizar que todos los recursos son liberados.

Herramientas de monitoreo

  1. Herramienta de monitoreo de memoria: Android Studio proporciona una herramienta de monitoreo de memoria que puede monitorear el uso de memoria de las aplicaciones en tiempo real durante el proceso de desarrollo, lo que ayuda a los desarrolladores a descubrir pérdidas de memoria de manera oportuna.

  2. DDMS: la herramienta DDMS en el SDK de Android puede monitorear los procesos y subprocesos de dispositivos o emuladores de Android, incluido el uso de memoria, seguimientos de pila y otra información, y puede usarse para diagnosticar pérdidas de memoria.

  3. MAT: MAT (Memory Analyzer Tool) es una herramienta de análisis de memoria basada en Eclipse que puede analizar el uso de memoria dinámica de las aplicaciones e identificar y localizar pérdidas de memoria.

  4. Matrix de Tencent también es un muy buen proyecto de código abierto y se recomienda que todos lo utilicen.

2. Resumen

Una pérdida de memoria significa que ciertos objetos o recursos en el programa no se liberan correctamente, lo que resulta en un aumento del uso de la memoria, lo que eventualmente puede provocar fallas de la aplicación o un funcionamiento lento del sistema.


Los problemas comunes de pérdida de memoria incluyen:

  1. Pérdidas de memoria causadas por mantener objetos Actividad o Fragmento durante mucho tiempo;

  2. Pérdidas de memoria causadas por clases internas anónimas y clases internas no estáticas;

  3. Pérdida de memoria causada por WebView que contiene el objeto Actividad;

  4. Pérdidas de memoria causadas por mantener objetos de recursos en modo singleton;

  5. Pérdidas de memoria causadas por recursos que no se cierran;

  6. Pérdidas de memoria causadas por variables estáticas que contienen objetos de contexto;

  7. Pérdida de memoria causada por que Handler contenga una referencia de clase externa;

  8. Pérdidas de memoria causadas por Bitmap que ocupa una gran cantidad de memoria;

  9. Pérdidas de memoria causadas por singletons que contienen grandes cantidades de datos.

Para evitar problemas de pérdida de memoria, podemos tomar las siguientes medidas:

  1. Liberar el objeto Actividad o Fragmento lo antes posible;

  2. Evite clases internas anónimas y clases internas no estáticas;

  3. Cuando utilice WebView, llame al método de destrucción lo antes posible;

  4. Evite mantener objetos de recursos durante mucho tiempo en modo singleton;

  5. Cerrar los objetos de recursos rápidamente;

  6. Evite variables estáticas que contengan objetos de contexto;

  7. Evite que Handler contenga referencias de clases externas;

  8. Cuando utilice Bitmap, libere memoria a tiempo;

  9. Evite los singleton que contengan grandes cantidades de datos.

Lo anterior es un resumen de la optimización del rendimiento de Android. Los escenarios de pérdida de memoria son diferentes y los métodos de optimización no son únicos. Todos pueden discutirlo juntos.

Supongo que te gusta

Origin blog.csdn.net/weitao_666/article/details/132336906
Recomendado
Clasificación