Você está na página 1de 17

Versión Estandar de Java JSE (Java Standar Edition) se usa para Aplicaciones de

escritorios

JEE se crean aplicaciones empresariales de gran escalas, anterior se conocía


como J2EE

MAQUINA VIRTUAL JAVA


Se crean clases java (Archivos de texto extensión java (.java)), estos archivos de
compilan por comando javac y genera código bytecode y tiene la extensión .class
y nos sirve para ejecutar el programa en distintos ambientes. Es una venta en
escribir nuestro código en java, ya que podemos crear nuestro archivo en
cualquier plataforma (Win, Mac, Linux).

Manejo de la memoria
Java simplifico mucho respecto al manejo de la memoria, fue la introducción del
manejo de recolector de basura. En java la asignación de datos y objetos en la
memoria ram se maneja de manera automática y el programador se enfoca en
cosas más importantes. Una vez que nuestro programa haya dejado de usar éste
espacio de memoria el recolector de basura detecta este espacio de memoria y los
limpia con el objeto de reutilizarlo.

Resumen de la Administración de Memoria y Garbage Collection


Finalmente vamos a meternos en el maravilloso mundo de la administración de la
memoria y el recolector de basura.

Consideremos que tenemos un programa que lee una gran cantidad de


información, digamos que de algún lado en la red, y entonces escribe todo esos
datos en una base de datos en el disco duro. Un diseño típico sería capaz de leer
la información en algún tipo de colección en memoría, realizar algunas
operaciones con la información, y entonces escribir los datos en la base de datos.
Después de que la información se haya escrito en la base de datos, la colección
que ha guardado la información temporalmente deberá estar lleno con información
antigua o borrada y debe ser recreada para el siguiente lote. Esta operación
podría ser realizada millones de veces, y en lenguajes como C o C++ que no
ofrecen una manera automática de recoger la basura, una pequeña imperfección
en la lógica que manualmente borra o vacía la estructura de datos en la colección
puede permitir pequeños montones de memoria a que sean impropiamente
reclamados o pordidos, para siempre. Estas pequeñas pérdidas de memoria son
llamadas “Memory Leak”, y tras varios cientos de iteraciones pueden hacer que
exista una cantidad suficiente de memoria inaccesible que hará que el programa
se cierre. Crear código que realice una administración de memoria manual de
manera limpia no es trivial y muy complejo, y si bien las estimaciones varían, es
discutible que la administración manual de la memoria puede doblar el esfuerzo
del desarrollo para un programa complejo.

El GC (Garbage Collector) de Java provee una solución automática de


administración de memoria. En la mayoría de los casos nos libera de tener que
añadir cualquier lógica de administración de memoria a nuestra aplicación. La
desventaja del GC automático es que no podemos completamente controlar
cuando see jecuta y cuando no lo hace.

Resumen del GC de Java

Vamos a ver que significa cuando hablamos sobre recolector de basura en los
campos deJava. El recolector de basura es la frase que se usa para describir la
administración de memoria automática en Java. Dondequiera que se ejecute un
programa (Ya sea en Java, C, C++, Lisp, Ruby, etc), este usa memoria de
diferentes maneras. Es típico para la memoria crear un stack, un heap, en el caso
de Java crear constant pools y áreas de método. El Heap es la parte de la
memoria donde los objetos de Java viven, y es la única que de cualquier manera
está envuelta en el proceso de recolección de basura.

Así, todo gira en torno a la recolección de basura asegurandose que el Heap tiene
suficiente espacio libre como le sea posible. Cuando el GC se ejecuta, su
propósito es buscar y borrar los objetos que no pueden ser alcanzados. Si
pensamos que un programa en Java es como un ciclo constante de creación de
objetos que se necesitan (los cuales ocupan espacio en el heap), y entonces se
van descargando los objetos que ya no son necesitados, creando nuevos objetos,
descartandolos, y así, la pieza que nos falta para completar el puzzle es el GC.
Cuando se ejecuta, busca todos esos objetos descartados y los borra de la
memoria para que el ciclo de uso de memoria y liberandose pueda continuar.

¿Cuándo se ejecuta el GC?

El G está bajo el control de la JVM. La JVM decide cuando se ejecuta el GC.


Desde dentro de nuestro programa Java podemos decirle a la JVM que ejecute el
GC, pero no hay garantías, bajo ninguna circunstancia de que la JVM cumpla con
esto. La JVM ejecutará típicamente el GC cuando sienta que la memoría está
siendo baja. La experiencia nos indica que cuando nuestro programa Java solicita
una recolección de basura, la JVM nos garantizará nuestra solicitud a corto plazo,
pero no hay garantías de ello.
¿Cómo funciona el GC?

No podemos estar seguros. Podemos haber escuchado que el GC usa un


algoritmo de marca y barrido, y para cualquier implementación de Java dada esto
puede ser verdad, pero la especificación de Java no garantiza cualquier
implementación particular. Podemos haber oido que el GC usa un contador de
referencia; una vez mas puede ser o no puede ser. El concepto importante es
entender cuando un objeto se convierte en elegible para el GC. Para responder a
esto deberemos dar un salto y hablar un poco sobre los Threads. Los programas
en Java, tienen desde uno hasta varios threads (hilos). Cada thread tiene su
propio stack de ejecución. normalmente, el programador hace que se ejecute un
hilo en Java, el que usa el método main(). Hay mas razones por las que se puede
lanzar threads adicionales desde neustro thread principal. En adición a tener su
propio stack de ejecución, cada thread tiene su propio ciclo de vida. Por ahora,
todo lo que necesitamos saber es que los threads pueden estar vivos o muertos.
Con esta información de fondo, podemos decir con claridad que un objeto es
elegible para el GC cuando ningún thread vivo puede acceder a el.

Basados en esta definición, el GC hace algo mágico, operaciones desconocidas, y


cuando descubre un objeto que no puede ser alcanzado por cualquier thread vivo,
se considera que el objeto es elegible para el borrado. Cuando hablamos sobre
alcanzar un objeto, estamos hablando realmente sobre tener al alcance su
variable de referencia que refiere al objeto en cuestión. Si nuestro programa Java
tiene una variable de referencia que se refiere a un objeto, y esa variable de
referencia está disponible en un thread vivo, entonces el objeto es considerado
alcanzable. Hablaremos mas sobre como los objetos pueden ser inalcanzables en
la siguiente sección.

¿Puede una aplicación Java quedarse sin memoria? Si. El sistema de recolección
de basura intenta eliminar objetos de la memoria cuando no son usados. Sin
embargo, si mantenemos muchos objetos viviendo el sistema puede quedarse sin
memoria. La recolección de basura no puede asegurar que haya suficiente
memoria, solo que la memoria que esté disponible pueda seradministrada de la
manera mas eficiente como sea posible.

Escribir código que explícitamente haga objetos elegibles para la Recolección

En la sección anterior, aprendimos las teorías tras el GC de Java. En esta sección,


vamos a ver como hacer que los objetos sean elegibles para la recolección
usando código actual. También discutiremos como intentar a forzar la recolección
si es necesario, y como podemos realizar limpieza adicional en objetos antes de
que sean removidos de la memoria.
Haciendo Null una referencia

Como discutimos anteriormente, un objeto se convierte en elegible para la


recolección de basura cuando no hay mas referencias accesibles a el.
Obviamente, si no hay referencias accesibles, no importa que le pase al objeto.
Para nuestro propósito es solo algo flotando en el espacio, sin usar, inaccesible, y
que no se necesite más.

La primera forma de remover una referencia a un objeto es establecer su variable


de referencia para que el objeto se refiera a null. Veamos el siguiente ejemplo:
public class GarbageTruck {
public static void main (String[] args){
StringBuffer sb = newStringBuffer("Hola");
System.out.println(sb);
// El objeto StringBuffer no es elegible para la sb = null;
// Ahora el objeto StringBuffer es elegible para la recolección
}
}
El objeto StringBuffer con el valor “hola” es asignado a la vriable de referencia sb
en la tercera línea. Para hacer el objeto elegible para el GC, establecemos la
variable de referencia sb a null, lo cual remueve la referencia que existía al objeto
StringBuffer. Una vez que la línea 6 se ha ejecutado, nuestro objeto StringBuffer
es elegible para la recolección.

Reasignando a la Variable de Referencia

Podemos tambien desacoplar una variable de referencia de un objeto


estableciendo la variable de referencia para que refiera a otro objeto. Veamos el
siguiente ejemplo de código:
public class GarbageTruck {
public static void main (String[] args){
StringBuffer s1 = new
StringBuffer("Hola"); StringBuffer s2 = new
StringBuffer("Adios"); System.out.println(s1);
// El StringBuffer "hola" no es elegible
s1 = s2; // Redireccionamos s1 para que se refiera al objeto "Adios"
// Ahora el StringBuffer "Hola" es elegible para la recolección
}
}
Los objetos que son creados en un método también necesitan ser considerados.
Cuando un método es invocado, cualquier variable local creada existe solo
mientras el método exista. Una vez que el método ha retornado, el objeto creado
en el método es elegible para el GC. Hay una excepción obvia, sin embargo. Si un
objeto es retornado desde un método, su referencia puede ser asignada a una
variable de referencia en el método que lo ha llamado; por lo tanto, no será
elegible para la recolección. Veamos el siguiente código:
public class GarbageFactory {
public static void main (String[] args){
Date d = getDate();
doComplicatedStuff();
System.out.println("d = " +d);
}

public static Date getDate(){


Date d2 = new Date();
StringBuffer now = new
StringBuffer(d2.toString());
System.out.println(now);
return d2;
}
}
En el ejemplo anterior, hemos creado un método llamado getDate() que retorna un
objeto Date. Este método crea 2 objetos, uno Date y otro StringBuffer que contiene
la información de la fecha. Ya que el método retorna un objeto Date, no será
elegible para la recolección incluso después de haber terminado el método. El
objeto StringBuffer, al contrario, si será elegible, aunque no hayamos establecido
explicitamente la variable now a null.

Aislar una Referencia

Hay otra manera por la cual los objetos pueden convertirse en elegibles para la
recolección, incluso si siguen manteniendo referencias válidas. A este escenario le
llamaremos “Islas de Aislamiento”.

Un ejemplo simple es una clase que tiene una variable de instancia que es una
variable de referencia a otra instancia de la misma clase. Ahora imaginemos que 2
instancias existen y que se refieren la una a la otra. Si todas las otras referencias
de estos 2 objetos fueran removidas, entonces incluso cada objeto mantendría
una referencia válida, no habría manera para cualquier thread vivo de acceder a
estos objetos. Cuando el GC se ejecuta, puede usualmente descubrir cualquier
isla de objetos y removerlos. Como podemos imaginar, tales islas pueden ser
grandes, teóricamente conteniendo cientos de objetos. Examinemos el siguiente
código:
public class Island {
Island i;
public static void main (String[] args){
Island i2 = new Island();
Island i3 = new Island();
Island i4 = new Island();
i2.i = i3; // i2 refiere a i3
i3.i = i4; // i3 refiere a i4
i4.i = i2; // i4 refiere a i2
i2 = null;
i3 = null;
i4 = null;
// Otras operaciones
}
}
Cuando el código alcanza el comentario // Otras operaciones, los 3 objetos Island
(previamente conocidos como i2, i3 y i4) tienen variables de referencia que se
refieren el uno al otro, pero para el mundo exterior han sido establecidos a null.
Estos 3 objetos son elegibles para el GC.

Forzar la Recolección de Basura o el Garbage Collection

Lo primero que deberíamos mencionar aquí es que, al contrario que al título de la


sección, el GC no puede ser forzado. Sin embargo, Java provee algunos métodos
que permiten solicitar a la JVM a que realice un GC.

El GC ha evolucionado hasta un estado avanzado en el que es recomendable que


nunca invoquemos System.gc() en nuestro código, dejemos esto a la JVM.

En realidad, es posible solo sugerir a la JVM que realice un GC. Sin embargo, no
hay garantías de que la JVM actualmente elimine todos los objetos que no se usen
de la memoria.

Las rutinas del GC que Java provee son miembros de la clase Runtime. La clase
Runtime es una clase especial que tiene un objeto singular (Singleton) para cada
programa main. El objeto Runtime provee de un mecanismo para comunicarse
directamente con la máquina virtual. Para obtener la instancia de Runtime,
podemos usar el método Runtime.getRuntime(), el cual nos retorna el Singleton.
Una vez que tenemos el Singleton podemos invocar el GC usando el método gc().

Alternativamente, podemos llamar al mismo método en la clase System, el cual


tiene métodos static que pueden hacer el trabajo de obtener el Singleton por
nosotros. La manera más simple de preguntar al GC es:
System.gc();

Teóricamente, después de llamar a System.gc(), obtendremos la mayor memoria


libre como nos sea posible. Decimos teóricamente porque esta rutina no siempre
trabaja de esta manera. Primero, nuestra JVM puede no implementar esta rutina;
la especificación del lenguaje permite a esta rutina de no hacer nada en absoluto.
Lo segundo, otro thread puede coger cierta memoria después de ejecutar el GC.

Esto no quiere decir que System.gc() sea un método que no sirva de nada (Es
mejor que nada). Simplemente no podemos confiar en que System.gc() libere la
suficiente memoria para que no nos tengamos que preocupar de no quedarnos sin
ella.
Ahora que estamos algo mas familiarizados con el como funciona, vamos a ver un
pequeño experimento para ver si podemos ver los efectos del GC. El siguiente
programa nos permite saber de cuanta memoria dispone la JVM y cuanta memoría
libre tiene. Entonces, crearemos 10.000 objetos Date. Despues de esto, nos dirá
cuanta memoría queda libre y entonces llamaremos al GC (El cual, decidirá si se
ejecuta o no). La memoria libre final resultante debería indicar cuando se ha
ejecutado. Vamos a ver el programa:
public class CheckGC {
public static void main (String[] args){
Runtime rt = Runtime.getRuntime();
System.out.println("Memoria Total de la JVM: " +
rt.totalMemory()); System.out.println("Memoria Antes: " + rt.freeMemory());
Date d = null;
for (int i = 0; i < 10000; i++){
d = new Date();
d = null;
}
System.out.println("Memoria Despues: " + rt.freeMemory());
rt.gc();
System.out.println("Despues del GC: " + rt.freeMemory());
}
}
Como podemos ver si ejecutamos el programa, la JVM decidió cuando usar el GC
para los objetos elegibles. En el ejemplo anterior, le sugerimos a la JVM a realizar
un GC cuando terminamos el bucle, y nos honra con nuestra petición. Este
programa solo tiene un thread siendo ejecutado, por lo que no había nada mas
ejecutandose cuando llamamos al método rt.gc(). Tenemos que tener en mente
que el comportamiento de cuando el gc() es llamado puede ser diferente según las
JVM, por lo que no hay garantías de que los objetos sin uso sean removidos de la
memoria. Lo único que podemos garantizar es que si hay poca memoria, el GC se
ejecutará antes de que se lance la excepción OutOfMemoryException.
Ambiente ejecución Java

En java hay 2 tiempos importantes al momento de crear y ejecutar el programa:

Tiempo de compilación: aquí se pueden encontrar varios errores y se deben


corregir para que nuestro programa pueda compilar de la manera correcta (Aquí
se ejecuta el comando Javac), en netbeans lo hace de forma automática.

Tiempo de ejecución: Cuando el programa compila de forma correcta, aquí


estaremos en tiempo de ejecución y en este proceso se ejecutan varias cosas
como: la clase principal, luego se carga en memoria y se revisa que todo esté en
orden por medio del verificador bytecode, luego se ejecuta el intérprete de java, el
cual hace el proceso transparente para nosotros de ejecutar nuestro archivo
.class en cualquier plataforma que tenga una JVM (Permite ejecutar nuestro
programa sobre el hardware y SO seleccionado)
Variables Java
Para almacenar información necesitamos variables, la cual nos guardará datos de
manera temporal. El objetivo de declarar variables es reservar espacio de
memoria dependiendo del tipo que vayamos a utilizar. Éstas variables nos
permiten hacer programas dinámicos por lo que en la mayoría de los casos los
datos cambiarán durante la interacción con el usuario y el programa

Tipos de datos Java

RANGO
NOMBRE TIPO OCUPA
APROXIMADO

byte Entero 1 byte -128 a 127

short Entero 2 bytes -32768 a 32767

int Entero 4 bytes 2*109

long Entero 8 bytes Muy grande


TIPOS PRIMITIVOS
(sin métodos; no son Decimal
float 4 bytes Muy grande
objetos; no necesitan simple

una invocación para


Decimal
ser creados) double 8 bytes Muy grande
doble

TIPOS DE Carácter
char 2 bytes ---
DATOS simple
EN JAVA
Valor true o
boolean 1 byte ---
false

String (cadenas de texto)


Tipos de la biblioteca
Muchos otros (p.ej. Scanner, TreeSet,
estándar de Java
ArrayList…)
TIPOS OBJETO
(con métodos, Tipos definidos por el Cualquiera que se nos ocurra, por ejemplo

necesitan una programador / usuario Taxi, Autobus, Tranvia

invocación para ser Serie de elementos o formación tipo vector o


creados) arrays matriz. Lo consideraremos un objeto especial
que carece de métodos.

Tipos envoltorio o Byte


wrapper (Equivalentes Short
a los tipos primitivos
Integer
pero como objetos.)
Long

Float

Double

Character

Boolean

En caso de cadenas:
Clases en Java
Una clase genera un nuevo tipo de datos en java. Una vez definidos esos datos
entonces lo podemos utilizar para poder crear objetos del tipo declarado.

Una clase es una plantilla de la cual podemos de la cual podemos crear más
objetos, debido a que un objeto es una instancia de una clase, normalmente
utilizaremos objetos (Los objetos son una instancia de una clase).
Palabra new reserva espacio de memoria para el objeto

Los tipos de clases (String, Integer,Boolean, etc. Son estáticas, lo cual no se


tienen que instanciar (String s = new String()))

Você também pode gostar