Cercanias Offline

Desde hace un tiempo quería introducirme en el mundo de desarrollo de aplicaciones Android y a principio de verano empecé a diseñar una aplicación que rondaba por mi cabeza desde que hace unos años Kendersec me dio la idea.


¿Quieres conocer los horarios de Cercanías Renfe y no dispones de internet en el móvil o tu tarifa de datos está muy limitada?

Con RenfeOffline Cercanias offline puedes consultar los horarios de los trenes de cercanías de Renfe sin necesidad de estar conectado a internet.

Tras descargar la base de datos de las ciudades que desees, podrás realizar las consultas sin consumir datos de internet. De este modo podrás obtener las bases de datos mediante wifi y preservar los Mb de tu tarifa para cosas más importantes.

Entre sus características se encuentran la visualización de los trasbordos y los tiempos de viaje. Además cuando una base de datos se caduque, la aplicación te lo comunicará para que la actualices, solo tendrás que descargarte la base de datos sin tener por que actualizar la aplicación.

Recordar que RenfeOffline no obtiene los datos de internet, por lo que en días especiales en los que por alguna causa Renfe modifique sus servicios, los datos obtenidos no serán totalmente fiables. Este caso puede darse en días de partidos o días en los que los operarios de Renfe hacen huelga.

Solo están disponibles las Ciudades contempladas en Renfe Cercanias, éstas son:

  • Asturias
  • Barcelona
  • Bilbao
  • Cádiz
  • Madrid
  • Málaga
  • Murcia y Alicante
  • Santander
  • San Sebastián
  • Sevilla
  • Valencia
  • Zaragoza

Podéis adquirir la aplicación entrando al Android Market .

Podéis encontrar más información sobre la aplicación en la página dedicada a la misma de mi blog.

Cualquier crítica constructiva o reporte de errores serán bienvenidos en mi email: finxnif@gmail.com o mediante la cuenta de twitter @CercaniaOffline.

Archivos y carpetas ocultas en Mac OS X

Hasta la fecha, nunca me ha hecho falta ver carpetas ocultas desde le finder, pues suelo gestionar mis ficheros desde la consola de comandos. Hoy me he encontrado con un pequeño problema cuando he querido poder acceder a unos archivos generados por una aplicación bajo un directorio oculto y tras repasar las opciones de visualización del finder no he encontrado nada.

Tras buscar un poco por la red he encontrado un modo que pese a resultar un poco engorroso en el caso de que no queramos hacer permanente la visualización de los mismos, funciona correctamente.

Para ello tenemos que abrir un terminal e introducir

defaults write com.apple.finder AppleShowAllFiles TRUE

Tras ello tendremos que reiniciar el navegador de archivos, para ello pulsamo: ‘cmd+alt+esc’ y en la lista que aparece seleccionamos el finder y pulsamos sobre ‘forzar salida’.

Ahora ya podríamos ver todos los archivos y directorios ocultos del sistema.

El truco funciona igual si en lugar de TRUE se pone un ON.

defaults write com.apple.finder AppleShowAllFiles ON

Del mismo modo podemos recuperar la normalidad de nuestro sistema cambiando TRUE por FALSE u OFF.

defaults write com.apple.finder AppleShowAllFiles FALSE
defaults write com.apple.finder AppleShowAllFiles OFF

Espero que este pequeño howto os sea de utilidad.

Hasta pronto

Optimizando los IF al programar

Cualquier programador sabe que las sentencias condicionales son junto a los bucles unas de las estructuras más empleadas ya que nos permiten ejecutar un aparte del programa u otra dependiendo de diferentes factores. El caso de los IF resulta tan trivial, que pocos son los que se plantean que dependiendo de como se construyen pueden afectar al rendimiento de sus aplicaciones.

En el presente artículo vamos a centrarnos en el caso de Java, aunque es aplicable a la mayoría de los lenguajes de programación existentes.

Para comenzar veamos algunos conceptos muy simples de como se ejecutan las sentencias condicionales más famosas. Me gustaría aclarar que se  da por hecho que el lector conoce los conceptos más básicos de los IFs. Esta prueba podéis hacerla usando un debugger y separando las condiciones en diferentes lineas.

OR

El comportamiento de la condición OR, ejecuta todas las expresiones ha analizar hasta encontrar una que resulte cierta y procesa lo correspondiente.

if (TRUE || 1==2){
   //TODO
}

En este primer caso, nunca se llegaría a analizar la condición ‘1==2’ ya que una vez llegado al ‘TRUE’ se ejecutaría el código.

if (FALSE || 1==1){
   //TODO
}

En este otro caso, se comprobaría que la primera condición no es cierta por lo que se procedería a comprobar la siguiente.

De esta lección podemos aprender que hay que poner por delante aquellas expresiones que tengan una mayor probabilidad de ser ciertas o aquellas que consuman menos ciclos de procesador (calcular el módulo ‘%’ consume más que una igualación ‘==’), a fin de que se ejecuten la menor cantidad de comprobaciones.

AND

Las condiciones unidas por un AND se ejecutan siempre de principio a fin hasta encontrar una que no sea cierta. En el caso de que ninguna de las condiciones resulte FALSE, se ejecuta el código pertinente. En el momento en el que una resulte FALSE, se sale del programa.

En el siguiente bloque de código se muestran unas condiciones, las primeras unidas por AND  y las segundas mediante IFs anidados, su ejecución es la misma.

//Unión mediante AND
if (a ==b && b==c){
  //TODO
}

//Unión mediante anidación
if (a==b){
  if(b==c){
    //TODO
  }
}

Como en el caso de OR, se muestran unos ejemplos a fin de explicar con mayor claridad el funcionamiento del AND.

if (2==2 && 1==1){
   //TODO
}

En este primer ejemplo se comprobaría en primera instancia el ‘2==2’ y al resultar TRUE, se pasaría a analizar el ‘1==1’.

if (2==1 && 1==1){
   //TODO
}

En esta ocasión pese a que la segunda condición sea cierta, el programa nunca llega a comprobarla pues la primera ya ha resultado ser FALSE.

Como probablemente sabrás, para evitar ciertos problemas a la hora de programar en Java, hay que tener muy claro como se ejecutan las condiciones unidas por un AND, pero no voy a hacer referencia a ello pues no es el objetivo de esta entrada. Desde el punto de vista de la optimización, hay que tratar de poner por delante aquellas sentencias que tengan mayor probabilidad de ser FALSE y nuevamente aquellas que menos ciclos consuman de CPU. Si por ejemplo tenemos dos sentencias, una ‘a==b’ y otra que tenga cálculos más complejos como ‘a+15/b == c-18/d’, se ha de optar por poner antes la primera de ellas.

OTROS CONSEJOS

Hay otro consejo que resulta tan obvio que muchos no se dan cuenta, cuando tenemos un bucle en el que hay un IF con varias comprobaciones y una o varias de ellas no cambian, es recomendable hacer esa comparación fuera y almacenarla como variable boolean ya que es más rápido comparar ésta que toda la secuencia.

String a = "hola";
int cont =0;
while ( cont <100){
    if((a.compareToIgnoreCase("Hola")==0 && ....){
           //TODO
    }
    cont++;
}

Podría sustituirse por este otro código en el que el ‘compareToIgnoreCase’ solo se realiza una vez y no una vez en cada bucle.

String a = "hola";
boolean b=a.compareToIgnoreCase("Hola")==0;
int cont =0;
while ( cont <100){
    if((b<strong> </strong>&& ....){
        //TODO
     }
    cont++;
}

EJEMPLO PRÁCTICO

El programa que se muestra a continuación toma una lista de números, un rango y un número y clasifica todos los números de la lista en diferentes ArrayList dependiendo de si es un múltiplo del numero dado dentro del rango, si es múltiplo pero no está comprendido en el rango o si no es múltiplo.

Se trata de un caso muy simple, pero como podrá comprobarse, cuando se ejecuta repetidas veces, pueden notarse ligeras diferencias entre unos casos y otros, lo suficiente como para cuando tengamos sentencias condicionales dentro de bucles nos pensemos un par de veces el orden adecuado antes de escribir el código.

La clase Main

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class Launcher {
	private final static int ini=30;
	private final static int fin=500000;
	private final static int num=3;

	private final static int numTest=1000;

	public static void main(String[] args) {
		int cont;
		Launcher launcher = new Launcher();
		ArrayList list = new ArrayList();

		for(cont =1; cont<=999999;cont++){
 			list.add(cont);
		}

		//Modelo A
		System.out.println("MODELO A");
		launcher.impHora();

		MultiplosA pruebaA = new MultiplosA();
		for (cont=0;cont<numTest;cont++){
			pruebaA.getMultiplos(list, ini, fin, num);
		}

		launcher.impHora();

		//Modelo B
		System.out.println("MODELO B");
		launcher.impHora();

		MultiplosB pruebaB = new MultiplosB();
		for (cont=0;cont<numTest;cont++){
			pruebaB.getMultiplos(list, ini, fin, num);
		}
		launcher.impHora();

		//Modelo C
		System.out.println("MODELO C");
		launcher.impHora();

		MultiplosC pruebaC = new MultiplosC();
		for (cont=0;cont<numTest;cont++){
			pruebaC.getMultiplos(list, ini, fin, num);
		}
		launcher.impHora();
	}

	private void impHora(){
		Calendar calendario = new GregorianCalendar();
		int hora, minutos, segundos, ms;
		hora =calendario.get(Calendar.HOUR_OF_DAY);
		minutos = calendario.get(Calendar.MINUTE);
		segundos = calendario.get(Calendar.SECOND);
		ms = calendario.get(Calendar.MILLISECOND);
		System.out.println(hora + ":" + minutos + ":" + segundos+":"+ms);
	}
}

Este es un simple programa que genera una ArrayList con los primeros 999999 números. Posteriormente se pasa esta lista a diferentes clases que como veremos realizan la función anteriormente descrita. Junto a la lista de números se establece un margen inferior (ini) y uno superior (fin) junto con el número del que buscamos los múltiplos (num). Al inicio del programa puede observarse una tercera variable numTest la cual indica cuantas veces se ha de ejecutar cada una de las llamadas a la función.

Se ha añadido una función ‘impHora()’, encargada de mostrar la hora actual del equipo antes y después de haber ejecutado cada prueba.

La prueba se realiza varias veces a fin de obtener unos tiempos significativos para compararlos con mayor facilidad.

En los siguientes bloques de código se exponen las tres clases empleadas en el ‘MultiplosA’, ‘MultiplosB’ y ‘MiltiplosC’. Las clases implementan el mismo método ‘getMultiplos(…)’ al cual pasamos una lista de números en la que buscar, un número mínimo y máximo. El programa almacena en tres ArrayList diferentes:

  • multiplosEntre: Son los múltiplos del 3 comprendidos en el rango indicado.
  • multiplosOtros: Son los múltiplos del 3 que no se encuentran dentro del rango.
  • noMultiplos: El resto de los números.
Se aclara que estas variables se incluyen dentro de la función y no como globales a fin de ahorrar memoria al repetir la llamada a la función múltiples veces, evitando así dejar al equipo sin recursos.
La única diferencia entre los códigos es como están construidos los IFs.
import java.util.ArrayList;

public class MultiplosA {

	public  void getMultiplos(ArrayList list, int ini, int fin, int num){
		int cont=0;
		ArrayList multiplosEntre = new ArrayList();
		ArrayList multiplosOtros = new ArrayList();
		ArrayList noMultiplos = new ArrayList();

		while (cont < list.size()){
 			int a = list.get(cont);
 			if (a%3 == 0 && a>=ini && a<=fin){
 				multiplosEntre.add(a);
			}else if(a%3 == 0 &&( afin)){
				multiplosOtros.add(a);
			}else if (a%3!=0){
				noMultiplos.add(a);
			}

			cont++;
		}
	}
}

En este primer código se hace lo más lógico, lo que en un principio haríamos todos, se tienen en cuenta todos los casos así como todas las condiciones a cumplirse en cada caso. En el próximo bloque veremos que podemos mejorar en este caso.

import java.util.ArrayList;
public class MultiplosB {
	public  void getMultiplos(ArrayList list, int ini, int fin, int num){
		int cont=0;
		ArrayList multiplosEntre = new ArrayList();
		ArrayList multiplosOtros = new ArrayList();
		ArrayList noMultiplos = new ArrayList();

		while (cont < list.size()){
 			int a = list.get(cont);
 			if (a>=ini && a<=fin && a%3==0){
 				multiplosEntre.add(a);
			}else if (( afin)&&a%3==0){
				 multiplosOtros.add(a);
			}
			else if (a%3!=0){
				 noMultiplos.add(a);
			}
			cont++;
		}
	}
}

En este caso, el primer y último IF se han dejado como en el anterior, pero en el segundo se han cambiado el orden de los operandos, ya que la comprobación de ‘menor y mayor que’ son más rápidas que el cálculo del resto.

import java.util.ArrayList;
public class MultiplosC {
	public  void getMultiplos(ArrayList list, int ini, int fin, int num){
		int cont=0;
		ArrayList multiplosEntre = new ArrayList();
		ArrayList multiplosOtros = new ArrayList();
		ArrayList noMultiplos = new ArrayList();

                while (cont < list.size()){
 			int a = list.get(cont);
 			if (a>=ini && a<=fin && a%3 == 0){
 				multiplosEntre.add(a);
			}else if (a%3==0){
				multiplosOtros.add(a);
			}else{
				noMultiplos.add(a);
			}

			cont++;
		}
	}
}

Este es el caso más óptimo de los tres presentados, en el ‘ELSE IF’ marcado, se omite comprobar que  está fuera del rango establecido, ya que si es múltiplo del 3 y no está comprendido dentro del rango (comprobado dos lineas más arriba), se encuentra fuera del mismo. Del mismo modo el último ‘ELSE IF’ ha sido sustituido por un ‘ELSE’ ya que el resto de números no será un múltiplo del 3.

RESULTADOS DE LOS TEST

El código superior ha sido ejecutado en mi MacBook Pro de 13” de principios del 2011 con un Intel Core i5 a 2,3GHz y 4 GB de DDR3 a 1333MHz bajo Mac OS X Lion 10.7.1.

Se han realizado dos pruebas idénticas pero con valores para ‘numTest’ diferentes, en la primera de ellas con 1000 y la segunda con 5000. Los resultados obtenidos son los siguientes

TEST 1000
MODELO A -- 2min 23seg
15:48:44:903
15:51:17:934

MODELO B -- 2min 21seg
15:51:17:934
15:53:38:394

MODELO C -- 2min 20seg
15:53:38:394
15:55:58:411

TEST 5000 MODELO A -- 12mn 38seg
19:29:43:139
19:42:11:631

MODELO B -- 11min 54seg
19:42:11:631
19:54:5:535

MODELO C -- 11min 37seg
19:54:5:535
20:5:42:455

Se puede observar con este rudimentario procedimiento como del Modelo A al resto de pruebas, hay una diferencia sustancial, sobretodo cuando se repite el proceso 5000 veces. En programas simples que se ejecuten en máquinas potentes, puede parecer absurdo pensar en ello, pero resulta interesante cuando nuestros programas van dirigidos a terminales como teléfonos móviles con recursos limitados y operaciones de cálculo más complejas, no olvidemos que la operación más costosa en el código de prueba a sido calcular el resto de una división.

En mi pequeña experiencia programando para Android, he conseguido optimizar la ejecución de parte de mi código gracias a darle un par de vueltas a que hay que comprobar y que no y en que orden se han de ejecutar las cosas. Esto ha supuesto que algo que en un Nexus One, se ejecutaba en 10 segundos, se viera reducido a 5. Cuando hablamos de terminales más modestos como es el caso de un HTC Magic, en el que el código antiguo tardaba cerca de 25 segundos, es algo que se agradece.

Un saludo y hasta pronto.

Trucos WordPress.com

Desde que comencé a emplear el servicio gratuito de WordPress.com me he encontrado con dificultades para conseguir cosas que en otros servidores de blogs se consiguen directamente desde el propio editor de textos enriquecido, sin necesidad de tener que editar el código HTML. Esta es una recopilación de esos trucos que yo he visto necesarios. Primero haré un repaso por los que se emplean durante la edición de texto, para luego enseñar algún otro.

JUSTIFICAR EL TEXTO

Desde el editor nos dan la opción de alinear el texto a la izquierda, a la derecha o centrarlo, pero de este modo, en mi opinión, los textos quedan muy poco estéticos. Para justificar nuestros textos basta con seleccionar los párrafos a los que queramos aplicar el cambio y pulsar la combinación de teclas [alt + shift + j].

INSERTAR CÓDIGO DE PROGRAMACIÓN

Es muy común en el mundo de la informática, tener que introducir trozos de código de programación, como pueden verse en mi entrada sobre La memoria en Java. Se hace directamente desde la edición de texto visual insertando el siguiente código:

[sourcecode language="java"]

Aquí metemos el código

[/sourcecode]

Todo lo que se introduzca entre esas etiquetas será representado literalmente y se resaltará dependiendo del lenguaje de programación que se especifique.

Se ha hablado sobre este truco más a fondo en esta otra entrada en la que se analizan todas las opciones que acepta.

TEXTO FLOTANTE AL PASAR EL RATÓN

No es algo muy común, pero a veces resulta más estético mostrar el significado de un acrónimo al pasar el ratón que hacerlo entre paréntesis, por ejemplo: JVM.

Para ello, se ha de acceder a la pestaña de edición HTML e introducir el siguiente código.

<abbm title="Java Virtual Machine">JMV</abbm>

Antes de comenzar  con trucos que no tienen nada que ver con la presentación de los textos, aclarar que cualquiera que sepa HTML puede realizar muchas más modificaciones desde la pestaña HTML del editor teniendo como única frontera su imaginación.

ESTADÍSTICAS DE VISITAS EXTERNO

En mi opinión, las estadísticas de visita que se muestran por defecto en WordPress.com deja mucho que desear, te indica desde que dominio accede alguien a tu web, pero no te especifica desde donde exactamente, por ejemplo, si tienes un visitante desde un Tweet de Twitter te indica que viene desde Twitter. Tampoco puedes saber desde que lugar del mundo acceden, lo que en muchas ocasiones puede ayudar mucho al escritor a decidir que expresiones emplear.

En mi anterior blog, empleaba el servicio de StatCounter, no es el más completo de todos los que se encuentran por la red, pero a mi me gusta y ya llevo unos años con él.

Todos estos servidores nos facilitan un código HTML que hay que añadir en la web a fin de que ellos puedan hacer el recuento de las visitas. Para realizar esto tendremos que acceder al panel de control de WordPress.com y seguir los siguientes pasos.

[Apariencia] > [Widgets]

Buscamos y añadimos el Widget de Texto al panel lateral derecho que nos aparece, y en el cuerpo del mensaje añadimos el código HTML. Yo en mi caso, he aprovechado el que introduje para poner la licencia a fin de no tener que añadir otro campo de texto más y he empleado un código invisible que no se ve, pero que cumple bien su función.

Insertar Código Fuente en WordPress.com

Si sóis usuarios de una cuenta gratuita en WordPress.com, habréis notado que no se permite editar los CSS, ni otras cosas que puedan ayudarnos a poder hacer más visual parte de nuestras entradas. Como programador, y devido a la temática de este blog, en muchas ocasiones me he visto obligado a introducir código fuente en diferentes lenguajes de programación, por lo que el haber encontrado un modo simple y rápido de introducir este código y que todos puedan verlo correctamente formateado, me alegró mucho.

Esto es a lo que me refiero:

class HolaMundo{

    public static void main(String[] args){

       System.out.println("Hola Mundo");

    }

}

Sus ventajas no son solo el aspecto visual, también que puede copiarse el contenido del mismo y que el escritor no tiene que andar aplicando estilos a cada parte del código para que este se vea con colorines.

El único problema que le veo es que no tabula automáticamente, pero si se copia desde un editor de texto normal, no hay problema con ello.

¿CÓMO SE CONSIGUE?

Es muy simple poner un cuadro como el de arriba, basta con itroducir en la pestaña ‘Visual’ del editor, he dicho la ‘Visual’ no la ‘HTML’, el siguiente código.

[sourcecode language="java"]
class HolaMundo{

public static void main(String[] args){

System.out.println(“Hola Mundo”);

}

}
[/sourcecode]

El parámetro ‘language’ admite multitud de lenguajes, a continuación se encuentra una lista completa.

  • actionscript3
  • bash
  • coldfusion
  • cpp
  • csharp
  • css
  • delphi
  • erlang
  • fsharp
  • diff
  • groovy
  • html
  • javascript
  • java
  • javafx
  • matlab (solo palabras claves)
  • objc
  • perl
  • php
  • text
  • powershell
  • python
  • r
  • ruby
  • scala
  • sql
  • vb
  • xml

Si no introducimos el parámetro ‘language’ se establece por defecto a ‘text’ esto es, texto sin modificaciones.

PARÁMETROS DE CONFIGURACIÓN

Hay multitud de parámetros de configuración aparate del de ‘language’ que ya hemos visto.

  • autolinks (true/false) — Establecer si se resaltan los links automaticamente. Por defecto True.
  • collapse (true/false) — Si está a True, el código aparecerá reducido y requerirá de la interacción de un usuario para expandirse, resulta ideal para código grande. Por defecto está a False.
  • firstline (número) — Si se quiere que la primera línea no sea la 1 puede modificarse, resulta útil cuando se corta código en diferentes diálogos.
  • gutter (true/false) —  Si se encuentra a False, no se mostrarán los números de línea. Por defecto está establecido a True.
  • highlight (número de lineas separados por comas ‘,’) —  Puedes marcar las líneas que quieras que sean marcadas de un modo especial para resaltar, por ejemplo “4,7,19″.
  • htmlscript (true/false) —  Si se encuentra en True, cualquier código HTML/XML que se introduzca será resaltado, es útil para cuando se mezcla código PHP con HTML por ejemplo. Por defecto se encuentra a False.
  • light (true/false) — Si se establece a True, tantos los números de las líneas como la barra de herramientas que aparece al poner el ratón sobre el cuadrado, no se muestran. Por defecto se encuentra a False.
  • padlinenumbers (true/false/integer) — Se emplea para establecer de cuantos dígitos constan los números que representan la linea. Si está a True, se establece en automático, en false no se realiza y si se introduce un valor numérico se establece éste. Por ejemplo al poner paddlinenumbers="3" la línea 1 se representaría como 001.
  • toolbar (true/false) — Si está a False, la barra de herramientas que se muestra al pasar el ratón por el código no se mostrará. Por defecto se encuentra a True.
  • wraplines (true/false) — Si se encuentra a False, las líneas de texto largas no van a ser cortadas provocando la aparición de una barra deslizante horizontal en el recuadro. Por defecto se encuentra a true.

EJEMPLOS

[sourcecode language="java" autolinks="true" wraplines="false" padlinenumbers="2" highlight="1,5"]

class HolaMundo{

    public static void main(String[] args){

       System.out.println("Hola Mundo, nos encontramos en https://ayddup.wordpress.com , visítanos siempre que te apetezca");

    }

}

[sourcecode language="java" autolinks="false" wraplines="true" gutter="false" ]

class HolaMundo{

    public static void main(String[] args){

       System.out.println("Hola Mundo, nos encontramos en https://ayddup.wordpress.com , visítanos siempre que te apetezca");

    }

}

Toda la información ha sido obtenida de la página de soporte de WordPress.com [ENG]

Obsolescencia programada

Nuestros padres y abuelos siempre nos lo han dicho, en su época las cosas se hacían para durar, ahora las cosas se hacen pensando en consumir. Lo más probable es que cuando adquiramos un producto, éste ya tenga una fecha determinada para morir, alguna de sus piezas han sido manipuladas para que esto suceda así. Teniendo en cuenta el tema, no puedo dejar hacer referencia a un documental emitido por RTVE hace un tiempo “Comprar Usar Comprar“. Dejo el enlace a Youtube ya que han quitado el vide de la web de RTVE.

En la época de consumismo en la que vivimos, es posible que no nos demos cuenta de esta realidad, pues antes de que a un producto le llegue su hora lo habremos sustituido por una nueva versión mejorada con unas prestaciones que posiblemente no precisemos pero que nos han hecho creer que son las que en ese momento determinado precisamos. Sin ir más lejos yo abandoné mi antiguo SmartPhone, un HTC Magic por mi actual Nexus One, y puede que no sea el mejor ejemplo, pero como yo muchos otros realizan esta práctica. Pero para todos aquellos que no crean que sus viejos aparatos tienen un mejor sustituto, se ha diseñado la Obsolescencia Programada, esto es, se programa cuando un producto tiene que dejar de funcionar.

Al igual que en el documental antes mencionado, voy a empezar hablando de un producto que conocemos todos, las impresoras. En el video nos muestran como la impresora de un chico deja de funcionar y tras investigar, contacta con un señor que le indica que la impresora tiene un chip que cuenta las páginas impresas y que alcanzado un número determinado se bloquea. La solución es reiniciar los datos de ese chip. Puede que esto no nos suceda a muchos, pero con otro componente del mismo aparato nos hemos peleado más de uno, la tinta.

En las impresoras convencionales la tinta suele venir divididas en 2 cartuchos diferentes, uno Negro y otro Tricolor, cian, amarillo y magenta. Mediante la combinación de estos se obtienen toda la gama de colores que vemos depositada en la bandeja de impresión. Por experiencia personal creo que hay unos momentos claves en la historia que han ido cambiando el modo en el que se consumía la tinta en nuestros hogares.

Al principio se adquirían los cartuchos originales pues no había más remedio, al cabo de los años, algunas marcas se arriesgaron a sacar cartuchos compatibles a un precio muchísimo más bajo, y luego pasamos a recargar la tinta. La industria, muy inteligentemente, se ha ido adaptando a los cambios del usuario. Una de sus primeras estrategias fue que si uno de los colores del cartucho tricolor se vaciaba, te informaba de que ese cartucho no tenía tinta. Uno podía dedicarse a imprimir folios en amarillo, y tras un rato no le dejaría imprimir uno magenta, peso a ne haber empleado ese color hasta el momento. Cuando los usuarios al ver esto empezaron a inyectar tinta a los cartuchos en casa a fin de mostrar a la impresora que todo estaba normal, los fabricantes limitaron el uso de impresiones de cada cartucho, si se decía que el cartucho negro podía imprimir 100 páginas, una vez llegadas esas páginas, ese cartucho era inservible, pues contenía un chip que le indicaba estar vacío pese a contener aún vida para unas cuantas páginas más.

Otro caso muy curioso en la historia es el de las bombillas, hubo un tiempo en el que las bombillas garantizaban una duración de 2.500 horas útiles, y de la noche a la mañana todos los fabricantes empezaron a garantizar que sus mejores bombillas solo duraban 1.000 horas. De este modo obligaban a los usuarios a adquirir nuevas bombillas en un menor tiempo mientras ellos no podían meter las manos en los bolsillos a cuenta de los billetes.

Dejando estos curiosos datos a un lado, y saliéndonos un poco de la temática del blog, vemos como ahora en todos los medios nos incitan a reciclar los productos que empleemos, papel, vidrio, embases, … Yo creo que esto es correcto, pero curiosamente parece ser que las mismas personas que nos lo dicen han olvidado que tal y como decía un antiguo profesor mío, en la vida de todo producto tendrían que haber 3Rs. Reducir, Reutilizar y Reciclar. Nos incitan a la última pero no nos piden reducir el consumo disparatado que llevamos, ni nos incitan a reutilizar las cosas. ¿Alguno tiene por casa una pluma estilográfica de su padre que se recarga con botes de tinta cuyo precio es muy inferior al de un bolígrafo desechable actual?

Espero haber dado a más de uno algo en que pensar, y si os interesa el tema ver el documental que he enlazado al principio de la entrada.

Un saludo

La memoria en Java, Garbage Collector y el método finalize()

A quien haya programado en lenguajes de programación tales como C, C++, o cualquier otro que permita un acceso real a la memoria, cuando se ha pasado a Java se habrá extrañado al no tener que ocuparse de la gestión de los recursos. Los conocidos métodos de C ‘malloc’ y ‘calloc’ pasan al olvido cuando programamos en este nuevo lenguaje, lo cual puede resultar cómodo, pero también puede generar ciertas dudas sobre quién y de que modo toma las decisiones de como se han de administrar los recursos de la memoria.

Antes de comenzar vamos a aclarar unos pequeños conceptos. La memoria está dividida en tres secciones diferentes, la Zona de Datos, Stack y Heap.

ZONA DE DATOS

Es donde se almacenan las instrucciones del programa, las clases con sus métodos y constantes (menos los finals). Esta zona de memoria es fija, y no se puede modificar durante el tiempo de ejecución.

STACK

El tamaño del Stack se define durante el tiempo de compilación y es estático durante su ejecución, por lo que puede llegar un momento en el que lo llenásemos y obtuviésemos un bonito StackOverflow que en java se representa mediante un ‘OutOfMemoryException’ . Es raro que nos encontremos con ello, pero si ejecutamos un método recursivo mal formado, es uno de los errores más comunes.

Los datos que se almacenan aquí son las referencias a objetos (instancias de objetos) y los datos primitivos como int, float o char. Cuando ejecutamos un método con variables locales, estas se cargan en el Stack y se eliminan una vez se finaliza el método.

El siguiente código generaría un StackOverflow, se trata de un ‘for’ infinito en modo recursivo.


public void meLlamoYoMismo(){

    meLlamoYoMismo();

}

HEAP

El Heap es la zona de memoria dinámica, almacena los objetos que se crean, en un principio tiene un tamaño fijo asignado por la JVM (Java Virtual Machine), pero según es necesario se va añadiendo más espacio.

STACK Y HEAP

Por lo que puede deducirse de las definiciones, el Stack y el Heap están estrechamente relacionados, ya que los objetos a los que apuntan las referencias almacenadas en el Stack se habrán creado en el Heap.


class MiClase{

    public static void main(String[] args){

        MiClase miObjeto;
        miObjeto = new MiClase();

    }

}

En la quinta linea se crea la referencia ‘miObjeto’ en el Stack y en la sexta se crea el objeto ‘new MiClase’ en el Heap y se enlaza ‘miObjeto’  a ella. Si la referencia ‘miObjeto’ apunta a otro objeto que se asigne en otro momento, el enlace anterior quedará roto y el objeto que se encuentra en el Heap no será enlazado por nadie ( Está consumiendo espacio en la memoria y no se hace uso de él).

Tiene que quedar claro que la relación referencia-objeto es de n-1, lo que quiere decir que un objeto puede ser apuntado por muchas referencias, pero que una referencia apunta a un solo objeto.

Otro ejemplo un poco más complejo que ilustra lo mismo que el anterior.


class MiClase{

    public static void main(String[] args){

        MiClase miObjeto;
        MiClase miOtroObjeto;
        miObjeto = new MiClase();
        miOtroObjeto = miObjeto;

        miOtroObjeto = new MiClase();

        miObjeto = null;
        miOtroObjeto= null;

    }

}

En las líneas cinco y seis se crean dos referencias de tipo ‘MiClase’ con los nombre ‘miObjeto’ y ‘miOtroObjeto’, en la siguiente se crea un objeto y se le asigna a la referencia ‘miObjeto’. En la línea ocho, tenemos ya dos referencias a ‘new MiClase()’, esto es, dos referencias a una misma instancia de objeto.

En la décima creamos otra nuevo objeto al que hace referencia ‘miOtroObjeto’, por lo que ya tenemos dos referencias a dos objetos diferentes. Las dos últimas lineas rompen esos enlaces al ser asignadas ambas referencias a null.

GARBAGE COLLECTOR

El Garbage Collector es un proceso de baja prioridad que se ejecuta en la JVM y es el encargado de liberar la memoria que no se emplea. El ser de baja prioridad supone que no pueda estar todo el rato trabajando, y que solo se le asigne su tarea cuando el procesador no tiene un trabajo con mayor prioridad en ejecución.

¿Cómo sabe el Garbage Collector lo que puede borrar y lo que no?  Es algo muy simple, si un objeto no tiene referencias desde el Stack tiene que ser eliminado.

La magia de este recolector de basura deja asombrados a los programadores que odian tener que gestionar la memoria ellos mismos, y es que es algo muy útil, pero se trata de un arma de doble filo. Entre sus contras tenemos que al tratarse de un proceso de prioridad baja, es poco probable que se ejecute cuando se esté haciendo un uso intensivo de la CPU. Esto se puede solucionar si se solicita una pasada del Garbage Collector desde el propio código. No se tiene que abusar de ello, pero puede resultar interesante tras una serie de operaciones que se sepa a ciencia cierta que puede dejar objetos sin referencias. El método de solicitar esta pasada se muestra en las siguientes lineas.

public void pasarGarbageCollector(){

    Runtime garbage = Runtime.getRuntime();
    garbage.gc();

}

El código que se muestra a continuación es un método de probar que esto efectivamente ayuda a liberar la memoria. Se realiza un bucle en el que se generan referencias y se eliminan las mismas y al terminar se solicita a la JVM que elimine todo objeto no referenciado. También se muestran por consola la memoria libre que se tenía antes y después de la petición.

class TestRecolector{

    public static void main(String[] args){

        TestRecolector test = new TestRecolector();
        test.testear();

    }
    public void testear(){
        Date fecha = null;
        for (int i = 0; i&lt;99999999;i++){
            fecha = new Date(2011,8,7);
            fecha = null;
        }

        this.pasarGarbageCollector();
    }
    public void pasarGarbageCollector(){

        Runtime garbage = Runtime.getRuntime();
        System.out.println(&quot;Memoria libre antes de limpieza: &quot;+ garbage.freememory());

        garbage.gc();

        System.out.println(&quot;Memoria libre tras la limpieza: &quot;+ garbage.freememory());
    }
}

Antes de continuar, mientras tenemos todo esto aun fresco, un consejo para programadores. En muchas ocasiones, al hacer operaciones, especialmente al trabajar con ‘ArrayList’ u otras listas, acostumbramos a emplear una variable temporal que solo resulta útil durante el tiempo de ejecución de esa operación. Cuando estas operaciones se hacen en un método externo al hilo principal no hay problema, pues sus “residuos” serán limpiados al salir del método, pero si por alguna razón se realizan en el hilo principal, o en un método que reúna múltiples operaciones (y que está largo rato ejecutándose), sería una buena idea que al terminar con el bucle se le asignara el valor ‘null’ a esas variables para dejar claro al Garbage Collector que ya no nos interesa mantenerla en memoria.

EL MÉTODO finalize()

El otro problema que supone el paso automático o descontrolado del Garbage Collector es que puede eliminar un objetos con información que queríamos guardar y que igual se ha quedado sin referencia por culpa nuestra. Por suerte, todas las clases heredan de ‘Object’ y con ello el método ‘finalize()’. Antes de que la JVM decida eliminar un objeto perdido, ejecuta este método. Gracias a ello podemos por ejemplo trabajar con una serie de elementos, eliminar la referencia a los mismos y no preocuparnos de guardar los datos esenciales en una base de datos (siempre que se reimplemente finalize() en ese objeto).

Dejo un método ilustrativo muy simple que muestra el funcionamiento de finalize();


public class Finalizando{

    String nombre;

    Finalizando (String pNombre){

        this.nombre = pNombre;

    }

    protected void finalize(){
        System.out.println(this.nombre);
    }
    public void pasarGarbageCollector(){

        Runtime garbage = Runtime.getRuntime();
        garbage.gc();
    }
    public static void main (String[] args){

        Finalizando persona = new Finalizando(&quot;Marta&quot;);
        persona = null;
        this.pasarGarbageCollector();

    }
}

El resultado de esto sería imprimir por consola “Marta”.
El ejemplo es algo banal, pero imaginemos que tenemos un ‘ArrayList<Persona>’ y que queremos recorrerlo mediante un while empleando un ‘miArray.remove(0)’ a fin de no tener que manejar un contador y sabiendo que no se emplearán de nuevo esos objetos una vez sus datos han sido almacenados en una base de datos. Para ello, pese a que no lo recomiende, puede implementarse el método ‘finalize()’ y despreocuparse uno de ello a posteriori.  Una cosa a tener en cuenta si se decide hacer esto, es que que nosotros dejemos sin referencia antes a un objeto que a otro, no implica que el Garbage Collector ejecute antes el ‘finalize()’ de ese objeto.

Espero que con esto tengáis más claro como se realiza la gestión de memoria en un entorno Java.

Un saludo y hasta pronto.