Java es un tipo de lenguaje de recolección de basura. Su ventaja es que los desarrolladores no necesitan administrar deliberadamente la asignación de memoria, lo que reduce la posibilidad de que las aplicaciones se bloqueen debido a las fallas de segmentación local y evita que la memoria no se debilite a exprimir la pila (montón). Por lo tanto, el código escrito es más seguro.
Desafortunadamente, todavía hay muchas fugas lógicas en Java que son propensas a la fuga de memoria. Si no tiene cuidado, su aplicación de Android puede desperdiciar fácilmente la memoria no libre, lo que eventualmente conducirá a un error de memoria que se agota (fuera de memoria, OOM).
1. La razón de la fuga de memoria general es que cuando se han liberado todas las referencias al objeto, el objeto no se ha liberado. (Nota del traductor: el cursor olvidó cerrar, etc.)
2. La razón de la fuga de memoria lógica es que cuando la aplicación ya no necesita este objeto, no se han liberado todas las referencias al objeto.
Si mantiene una fuerte referencia a un objeto, el recolector de basura no puede reciclar el objeto en la memoria.
En el desarrollo de Android, el problema de fuga de memoria más probable es el contexto. Por ejemplo, el contexto de actividad contiene una gran cantidad de referencias de memoria, como jerarquías de vista y otros recursos. Una vez que se filtra un contexto, también significa filtrar todos los objetos a los que señala. Las máquinas Android tienen memoria limitada, y demasiadas fugas de memoria pueden conducir fácilmente a OOM.
La detección de fugas de memoria lógica requiere un juicio subjetivo, especialmente el ciclo de vida del objeto no está claro. Afortunadamente, la actividad tiene un ciclo de vida claro y es fácil encontrar la causa de la fuga. Activity.ondestroy () se considera el final de la vida de la actividad. Programáticamente, debe destruirse o el sistema Android necesita reciclar esta memoria (nota del traductor: cuando la memoria es insuficiente, Android reciclará actividades invisibles).
Si este método se ejecuta, todavía hay una fuerte referencia a la actividad en la pila, y el recolector de basura no puede marcarlo como memoria reciclada, ¡y nuestro propósito original es reciclarla!
El resultado es que la actividad sobrevive fuera de su ciclo de vida.
La actividad es un objeto de peso pesado y debe ser manejado por el sistema Android. Sin embargo, las filtraciones de memoria lógica siempre ocurren inadvertidamente. (Nota del traductor: una vez probé una actividad que causó una fuga de memoria de 20 m). En Android, solo hay dos trampas que conducen a posibles fugas de memoria:
La variable estática del proceso global (proceso-global). Este monstruo que ignora el estado de la aplicación y tiene una fuerte referencia a la actividad.
Hilos que viven fuera del ciclo de vida de la actividad. No se eliminaron las referencias fuertes a la actividad.
Compruebe si ha encontrado las siguientes situaciones.
1. Actividades estáticas
La variable de actividad estática se define en la clase, y la instancia de actividad de ejecución actualmente se asigna a esta variable estática.
Si esta variable estática no se borra después del final del ciclo de vida de la actividad, causará una fuga de memoria. Debido a que las variables estáticas se extienden a través del ciclo de vida de esta aplicación, las actividades filtradas siempre existirán en el proceso de aplicación y el recolector de basura no recolectará.
actividad de actividad estática; void setstaticActivity () {actividades = this;} ver Sabutton = findViewById (R.ID.SA_BUTTON); Sabutton.SetOnClickListener (new View.onClickListener () {@Override public Void onClick (View V) {setStaticATIVY (); nextActivity;2. Vistas estáticas
Situaciones similares pueden ocurrir en el modo singleton, y si la actividad a menudo se usa, es práctico guardar una instancia en la memoria. Como se mencionó anteriormente, forzar el ciclo de vida de una actividad es bastante peligroso e innecesario, y no se puede hacer de todos modos.
Caso especial: si la inicialización de una vista consume muchos recursos y permanece sin cambios durante un ciclo de vida de la actividad, se puede convertir en estática y cargarse en la visión Hierachy. De esta manera, cuando la actividad se destruye, el recurso debe ser lanzado. (Nota del traductor: la memoria no se libera en el código de muestra. Simplemente nula esta vista estática, pero aún no se recomienda usar el método de vista estática)
vista estática; void setstaticView () {ver = findViewById (r.id.sv_button);} ver svButton = findViewById (r.id.sv_button); svbutton.setonclickListener (new View.OnClickListener () {@OverRide public void onClick (ver v) {setstaticView (); }});3. Clases de entrada
Continúe, suponiendo que haya una clase interna en la actividad, hacerlo puede mejorar la legibilidad y la encapsulación. Si creamos una clase interna y tenemos una referencia a una variable estática, felicidades, la fuga de memoria no está lejos de usted (nota del traductor: vacía cuando se destruye, um).
objeto estático privado interno; void createInnerClass () {Class InnerClass {} inner = new InnerClass ();} Ver icButton = findViewById (r.id.ic_button); icButton.setOnClickListener (new View.onClickListener () {@OverRide public void onClick (ver v) {CreateInnerClass ();Una de las ventajas de las clases internas es que pueden acceder a clases externas. Desafortunadamente, la razón de las filtraciones de memoria es que las clases internas tienen fuertes referencias a instancias de clase externas.
4. Clases anónimas
Del mismo modo, las clases anónimas también mantienen referencias a clases externas. Por lo tanto, las filtraciones de memoria son fáciles de ocurrir cuando define Asynctsk anónimo en su actividad. Cuando la tarea asincrónica ejecuta una tarea que lleva mucho tiempo en segundo plano, la actividad desafortunadamente se destruye (nota del traductor: las salidas del usuario, el reciclaje del sistema), esta instancia de actividad en poder de AsyncTask no será reciclada por el recolector de basura hasta que se complete la tarea asíncrona.
void startAsyncTask () {new AsyncTask <void, void, void> () {@Override void doinBackground (void ... params) {while (true); }} .execute ();} super.oncreate (saveDInStanceState); setContentView (r.layout.activity_main); ver aicButton = findViewById (r.id.at_button); aicButton.SetInScLickListener (new View.OnClickListener () { @ @ @ @ @ @ @ @ @ @ @ @ @@Soverride void (Vieid (View V) startAsyncTask ();5.Handler
Por el mismo token, defina anónima Runnable y ejecuta con un manejador de clase anónimo. La clase interna ejecutable tendrá una referencia implícita a la clase externa y se pasa a la cola de mensajes de mensajes del controlador. La instancia de actividad no se destruirá hasta que se procese el mensaje del mensaje, lo que resulta en una fuga de memoria.
void createHandler () {new Handler () {@Override public Void HandLemessage (mensaje Mensaje) {super.handlemessage (mensaje); }} .postdelayed (new runnable () {@Override public void run () {while (true);}}, long.max_value >> 1);} ver hbutton = findViewById (r.id.h_button); hbutton.setonClickListener (new View.onclickListener () {@overrice v) {createHandler ();6. Peques
Una vez más, mostramos fugas de memoria a través de Hild y TimeTk.
void spawnthread () {new Thread () {@Override public void run () {while (true); }} .start ();} Ver tButton = findViewById (r.id.t_button); tbutton.setOnClickListener (new View.OnClickListener () {@Override public void OnClick (View V) {SpawnThread (); NextActivity ();});7.TIMERTASK
Mientras sea una instancia de una clase anónima, independientemente de si está en el hilo del trabajador o no, mantendrá una referencia a la actividad, lo que dará como resultado una fuga de memoria.
void scheduleTimer () {new Timer (). Schedle (new TimeTask () {@Override public void run () {while (true);}}, long.max_value >> 1);} Ver ttButton = findViewByid (r.id.tt_button); ttbutton.setenClicklistener (newew.oncleNer () @Override public void onclick (ver v) {scheduletimer ();8. Gerente de Sensor
Finalmente, los servicios del sistema se pueden obtener a través de context.getSystemService (int name). Estos servicios funcionan en sus respectivos procesos, ayudando a las aplicaciones a manejar tareas de fondo e interacciones de hardware. Si necesita utilizar estos servicios, puede registrar oyentes, lo que hará que el servicio tenga una referencia al contexto. Si estos oyentes no se registran cuando la actividad se destruye, causará fugas de memoria.
void registreListener () {sensorManager sensorManager = (sensorManager) getSystemService (sensor_service); Sensor sensor = sensorManager.getDefaultSensor (sensor.type_all); sensorManager.registerListener (this, sensor, sensorManager.sensor_delay_fastest);} ver smButton = findViewById (r.id.sm_button); smbutton.setonClickListener (new View.OnClickListener () {@OverRide public void (View VeD) {RegisterListener ();Resumir
Habiendo visto tantos ejemplos que pueden conducir a fugas de memoria, es fácil comer toda la memoria de su teléfono, haciendo que la recolección y el procesamiento de basura con más frecuencia, e incluso en el peor de los casos, conducirá a OOM. Las operaciones de recolección de basura son caras y pueden conducir a retrasos visibles. Por lo tanto, preste atención a la cadena de referencia sostenida al instancias de instancias y, a menudo, realice verificaciones de fugas de memoria.