Artículos de Perl en Español

Uriel Lizama Julio 30, 2004
Usando la memoria en perl

Es muy importante que al crear algún desarrollo en perl, sepan controlar la memoria, lo peor que les puede pasar es que su servidor se quede sin recursos debido a que su CGI usa memoria excesiva.

Esto se potencializa si su CGI es usado por decenas, centenas o miles de personas al mismo tiempo, lo que puede generar verdaderos dolores de cabeza.

Esto se puede evitar de una manera rápida, y se hace comprendiendo cómo funciona la creación y destrucción de variables en perl.

En perl como en otros lenguajes como JAVA no nos tenemos que preocupar por la destrucción de nuestra variables para liberar memoria, pues el programa lo hace por nosotros. Sin embargo si podemos ayudar a perl a optimizar la manera en que destruye nuestras variables.

En primer lugar debemos de siempre y digo SIEMPRE usar variables locales, son pocas veces en las que realmente necesitamos variables globales.

La principal razón es que cuando usamos las variables locales estas tienen un "scope", el scope, término que se usa en inglés, es el alcance que tiene la variable.

Cuando una variable es declarada haciéndolo ya sea con my o con local (yo les recomiendo que siempre lo hagan con my), por ejemplo:

my $var;
local $var;

Al declararla ya tenemos un alcance, la variable será destruida cuando perl encuentre un "}". De esta manera si una variable es declarada al inicio de una función esta será destruida cuando perl encuentre el "}" final de la función, lo mismo pasa con los loops, enunciados de control, etc. es decir todo lo que tenga un par de "{}".

Sabiendo esto debemos de aprender a optimizar la manera en que declaramos nuestras variables.

Les voy a poner un ejemplo rápido, vean estos dos pedazos de código muy similares:

#EJEMPLO 1

my $i;

for($i=0; $i<10000; $i++){
#
}

EJEMPLO 2

for(my $i=0; $i<10000; $i++){
#
}

¿Se ven similares no? Pero fíjense donde estoy declarando la variable en el primer ejemplo, y donde lo estoy haciendo en el segundo ejemplo.

En el primer ejemplo al acabar el loop la variable $i quedará en memoria con el número "10000", lo que significa que usará algunos bytes de memoria mientras dure el programa.

En el segundo ejemplo, debido a que declare la variable en el loop esta será destruida al terminar el loop, liberando la memoria que esa variable este usando.

Con este sencillo ejemplo, aunque no muy grande, vemos como tiene suma importancia donde declaramos nuestras variables, ahorita no parecería importante, pero imagínense con variables que contienen megas o gigas de data.

Otro truco que se puede usar para salvar memoria es cuando leemos archivos.

Digamos que queremos leer un archivo y desplegar el contenido dentro de este. La primera opción que se nos ocurriría para hacerlo es:

open(FILE,"archivo.txt");
my @lines = <FILE>;
close(FILE);

foreach my $line(@lines){
print "$line";
}

Pero esta es una opción poco eficiente, analicen un poco el código y vean que pasa con el array, este se queda en memoria TODO el tiempo. Es decir mientras hacemos el loop foreach, en memoria tenemos el tamaño del archivo, más la variable que está leyendo cada línea. Ahora veamos otra opción:

open(FILE,"archivo.txt");

while(my $line = <FILE>){
print "$line";
}

close(FILE);

Ahora, esta opción es mucho más eficiente, pues el contenido del archivo nunca está en memoria. Solamente se usa memoria mientras cada línea del archivo esta en la variable $line que es destruida por perl en cada iteración del loop foreach. Y al finalizar el loop toda la memoria esta liberada.

Otra manera de salvar memoria es usando referencias. Pues de esta manera en vez de hacer copias de la misma variable, lo cual significa más memoria usada, mandamos una dirección en memoria para leer la variable ya antes creada, usando de esta manera casi nada de memoria más que aquella usada para guardar la dirección.

Para esto podemos ver dos ejemplos:

sub funcion_principal{
my @nombres = ('Uriel','Daniel','Gabriel');

print_nombres(@nombres);
}

sub print_nombres{
my @nombres = @_;

foreach my $nombre(@nombres){
print "$nombre\n";
}
}

Aquí tenemos dos funciones, la principal que se llama funcion_principal y la función print_nombres que lo que hace es recibir un array e imprimir el contenido del mismo.

El problema es que al recibir el array, tiene que ocupar más memoria para alojar el array recibido, por lo que mientras ejecutamos la función hay dos copias del array.

Esto para nada es eficiente y lo podemos evitar de la siguiente manera:

sub funcion_principal{
my @nombres = ('Uriel','Daniel','Gabriel');

print_nombres(\@nombres);
}

sub print_nombres{
my $ref_nombres = shift;

foreach my $nombre(@$ref_nombres){
print "$nombre\n";
}
}

Que fácil ¿verdad?, y sin embargo fue una gran optimización, pues ahora en vez de recibir el array y hacer una copia del mismo, la función print_nombres esta recibiendo la dirección en memoria en donde se encuentra el array, por lo que lo leemos directamente sin tener que hacer una copia.

Vemos como con un pequeños cambios podemos salvar varios kbytes de memoria, que si piensas, lo pueden usar miles de personas al mismo tiempo esto potencializando todo.

Vemos como podemos hacer muchas cosas para salvar el uso de memoria en nuestros CGIs y esto es sumamente importante para crear programas eficientes y útiles.

Otros Recursos Relacionados

Uriel Lizama es programador de perl y fundador de Perl en Español.
Comentarios

Formularios Web

Edwar:
Exelente la forma de explicar los problemas, te felicito tu articulo esta muy educativo y ademas muy intructivo.Gracias desde Barquisimeto Venezuela.

 
Edwar:
Exelente la forma de explicar los problemas, te felicito tu articulo esta muy educativo y ademas muy intructivo.Gracias desde Barquisimeto Venezuela.
 

Agrega tus comentarios










Recordar información personal?






[an error occurred while processing this directive]