Inicio > Android, C/C++, Java, Javascript, PHP, Programación > Reutilizando objetos para ahorrar tiempo y memoria en Java

Reutilizando objetos para ahorrar tiempo y memoria en Java


Aunque lo comento a raíz de una optimización que estoy realizando en una aplicación Android, es aplicable a Java y cualquier otro lenguaje.

Por lo general, estamos acostumbrados a crear objetos cada vez que lo necesitemos y a destruirlos una vez que ya no nos hagan falta, sin embargo, esto no es muy adecuado cuando vamos  a crear muchísimos objetos y a destruirlos tras un breve uso, pues el sistema tendrá que buscar un hueco de memoria, reservarlo, usarlo y borrarlo en cada ocasión.

Para solventarlo, lo mejor es reciclar objetos, lo cual se hace de una forma MUY sencilla.

Supongamos que tenemos un objeto Bala de un juego de disparos, del cual sabemos que crearemos miles y miles a lo largo de una partida. Podría ser algo así:


public class Bala {

    private int x;

    private int y;

    private float direccion;

    public Bala(int x, int y, float direccion) {

        this.x = x;

        this.y = y;

        this.direccion = direccion;

    }

}

Evidentemente necesitaría unos cuantos métodos más como el avanzar y tal, pero eso no nos concierne ahora, lo que nos preocupa es como poder volver a utilizar este objeto una vez no nos haga falta, como en nuestro caso, una vez choque contra el enemigo o salga de la pantalla.

El sistema es simple, una vez un objeto no lo necesitemos más, en vez de borrarlo, lo reciclamos y lo guardamos para cuando necesitemos uno nuevo.

Después, cuando necesitemos un objeto de este tipo, en vez de crearlo, miraremos si tenemos alguno guardado y si es así lo devolvemos, si no, creamos uno.

La clase finalmente podría quedar así:


public class Bala {

    private int x;

    private int y;

    private float direccion;

    private static LinkedList<Bala> balas = new LinkedList<Bala>();

    public Bala(int x, int y, float direccion) {

        this.x = x;

        this.y = y;

        this.direccion = direccion;

    }

         //Método estático que usaremos para obtener nuevas balas
         public static Bala getBala(int x, int y, float direccion) {

              //Si no tenemos elementos reciclados, creamos uno nuevo

           if (balas.isEmpty())

                 return new  Bala(x, y, direccion);

            //Si hay elementos, sacamos uno de la lista. Le ponemos los valores y lo devolvemos

            Bala bala = balas.removeFirst();
            bala.x = x;
            bala.y = y;
            bala.direccion = direccion;
            return bala;
     }

      //Una vez añadimos uno a reciclar NO debemos volver a usarlo, pues podríamos estar
      //usándolo en dos sitios distintos a la vez...
      public void reciclar() {
          balas.add(this);
      }
      //Cuando sepamos que no vamos a necesitar más ningún elemento, podemos borrar la lista
      //para no seguir almacenándolos en memoria.
      public static void borrarRecicladas() {
           balas.clear();
       }

}

Como podéis ver, la idea es muy simple y muy útil. Dependiendo de vuestras necesidades podéis modificarlo, como no guardar más de un máximo de elementos o borrarlos todos cada cierto tiempo.
En fin, espero que os sea de utilidad.

Anuncios
  1. 25 septiembre, 2011 en 5:03 pm

    Los “pools” son una idea muy vieja, chacho. Hay una cosa que se llaman soft-references que te ayuda a mantener esos objectos y evitar que el GC se los lleve. Amen.

    • 25 septiembre, 2011 en 5:09 pm

      Pues aún se sigue usando y recomendado su uso. Por ejemplo, con la clase Message de Android.

  2. 5 octubre, 2011 en 5:34 pm

    @jaberme: las soft references no son para “evitar” que el GC se los lleve, son para lo contrario: para que se los lleve si hace falta y si sólo están referenciados por soft references.

    En cuanto a reusar objetos, creo que el ejemplo no es del todo ilustrativo.
    Por lo que se ve se está reemplazando un new Bala() que hace 3 asignaciones por

    un isEmpty
    un removeFirst
    tres asignaciones

    Seguramente el GC trabaja un poco menos, pero se está ejecutando mucho más código.

    Para reusar objetos, lo recomendable es usar el profiler de netbeans o el que quieras, y mirar la estadística de creación de objetos por clase.

    A lo mejor el objeto Bala tiene un 20% que es mucho, pero tienes un 40% de Integer o de byte[].

    Los objetos inmutables son mucho más fáciles de reusar porque los puedes compartir.

    Un ejemplo, una aplicación que leía números del disco. Como los números estaban en su mayoría dentro del rango 0..10000, en lugar de hacer

    return new BigDecimal(numeroLeido);

    Hice un array de BigDecimal y los obtenía así:

    return numeroLeido > 10000 ? new BigDecimal(numeroLeido): NUMEROS[numeroLeido];

    Al ya tenerlos creados desde el principio, y ser al inmutables, no se creaban más BigDecimal dentro del rango.

    Pero lo importante es optimizar el objeto que más se está creando, según la información que te da el profiler. No tiene sentido optimizar un código que no tiene poco impacto.

  1. No trackbacks yet.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: