//English version --------------------------------------------------------------------------------
Hello everybody, I'm going to tell a story that happened a few months ago...
It turns out that I was working on a special project for "Exploratory Programming” and “Object Oriented Programming" (Systems Engineering curses of the “Universidad Nacional del Centro de la Provincia de Buenos Aires” - UNICEN)...
/** Below is a description of the project ... boring stuff */
The job consisted of implementing a Genetic Algorithm (GA) applied to the Project Scheduling Problem (PSP), with an interesting variant, human resources should be identified in order to define quality metrics for projects – the information about the performance of the resources for each activity were store in a relational Data Base (DB)...
So, the Application must generate project scheduling with optimal execution times, quality, costs, etc. criterions that will guide, by configuration, the GA by fitness functions.... (The work of a Project manager with experience in a business : P)...
/** Someone obtained a Ph.D in computer science for the theory behind this application, but it wasn’t me T_T ...*/
Anyway, the important data in order to consider are:
1.- The project was built with NetBeans IDE - after all, “Is the only IDE I need ".
2.- A GA Framework was design and implemented to provide all the settings that I needed on the GA to test the approach.
3 .- I use MySQL as database engine to persist all the information about the tasks, resources, costs, quality, etc.
4.- We modeled objects related to the context of the problem (projects, tasks, resources, etc.), in a separate project, the persistence was implemented by JDBC and DAOs... bad decision, I'm working on done via Hibernate at the moment because I'm trying it in my spare time 8-| (yes, I am a Sheldon) ...
5.- There was another project with the GA Framework hooks implementation on the specific domain, where points 1 and 4 were tied together , and implemented fitness function, chromosomes, genetic operators, etc.
6.- Finally a desktop Application (in Swing) was made to test whether all this really work (or if I just lost my time). This App allowed to create projects (or import them from the PSPLIB) - information regarding performance, cost, etc. was randomly seeded in the database - setup the GA at pleasure, and run it, to reach a set of alternative valid and good schedules for de input project.
Until here all great… turns up that my development process was a huge waterfall, and had left the testing for the last :P – I’m really confident about my code...
/** Important */
What is implicit earlier, and that is what really matters, is that the Application performs a large number of queries to the database for "qualities of performance”,” implementation costs”, etc. when evaluating the fitness of a chromosome (possible project schedule), and since big chromosome populations are managed, and a lot of iteration are made in the evolutionary process, until worthwhile plans are found… well you can imagine the number of accesses to the database... it was a lot!
Okay, it's time to test the Application and see what wonderful my code works (a very innocent thought of mine). At first, after fixing a few minor bugs, everything seemed to go well, the program responded correctly for small projects... but the goal was to support larger projects, so I started testing with the PSPLIB... and as expected, something went wrong...
The problem was a terrible VM Out of Memory error, my first solution was to increase the memory (-Xmm...), the result: it takes longer to run out of memory :P...
After futile efforts of debugging the monstrous application, and no desire to perform unit testing for each project separately ... and of course, convinced that my code was a masterpiece, but not even understand yet why it ran out of memory ...
At that time of bitterness (and fury), I saw the light (actually by chance I saw the "Profile Main Project" icon in the toolbar of my dear NetBeans), I had read about the new (at the time) “toy” for monitor memory, CPU, etc. in java applications, but had not tried it, and I thought, this is my last hope...
So there I was, profiling my project ... at first I thought it would be difficult, but after a few minutes you start to see how you can visualize a lot of your application interesting aspects with different chart...
And that's where I see the memory chart to grow to the overflow :(...
But I didn’t give up… my first assumption was that the chromosomes where causing memory leaks after each GA iteration… (yes, I click the “run Garbage Collector” button on the Profile view several times :P) ...
But by inspecting in detail the classes on the “Live Profiling Results” editor, I realized that the number of chromosomes instances remained constant, as it should be, actually all classes seemed to be within normal (back again, convinced that my code was a masterpiece :P)...
It was at that moment when I realize that most of the memory was consumed by String instances (and I did not engage in intensive work on Strings)... then I started to realize where the problem might be, but I was really tired, it was really late, and I went to sleep...
The next day I wake up with the idea that it was doing some out of control logging somewhere... but my logs do not show any abnormality... was then that I realized that I needed to review a log, the connection to the database... and, after reviewing the output (which was not the standard, so I had not seen it before), I realized that an SQL query was throwing an exception each time it runs (and ran a lot of times) and each time it logged the error... this log grew over the life of the program to leave it out of memory ...
At this point I must admit that as a fool, I had left an empty try/catch block... the only one with no error treatment, and it was the one who fails… it is destiny could say John Lock :P...
Anyway, after correcting the error (a “ quote instead of ‘ in a SQL query), everything worked wonderful, and so I could deliver the project ...
Morals of this tale:
* Never, never leave an empty catch block ...
* Never use a waterfall development process in a medium - large scale application...
* JDBC and DAOs can bring headaches ...
* The Profiler (Java VisualVM) can be very useful to inspect the behavior of an application at runtime...
* Combine this with a few hours of sleep can be very productive (did you never had a problem and the dreamed the solution???)...
Well, that was all my friends, I hope not to have bored you with my story...
See you!
carlitos.
//Spanish version -------------------------------------------------------------------------------
Hola a todos, les voy a contar una historia que paso hace ya unos cuantos meses...
Resulta que me encontraba realizando un trabajo práctico especial para las materias "Programación Exploratoria" y "Programación Orientada a Objetos" (Materias de la carrera Ingeniería en Sistemas de la Universidad Nacional del Centro - UNICEN)...
/** A continuación una descripción medio aburrida del trabajo… */
El trabajo consistía en implementar un Algoritmo Genético (AG) aplicado al problema de Planeamiento de Proyectos (PSP), con una variante interesante, los recursos humanos debían ser identificados individualmente para poder definir métricas de calidades de realización de proyectos en base a una base de datos que contendría la información del desempeño de los recursos (con una funcionalidad) para cada actividad... Es decir que la aplicación además de generar planes de realización de proyectos en tiempos óptimos, también podría realizarlos con una asignación de recursos optima en cuanto a calidades, costos, aprovechamiento, etc.... (El trabajo de un Project manager con experiencia en una empresa :P)…
/** Alguien obtuvo un doctorado en ciencias de la computación por la teoría tras esta aplicación, y no fui yo T_T...*/
En fin los datos importantes a tener en cuenta son:
1.- El proyecto fue programado íntegramente en NetBeans IDE - porque me copa el IDE, después de todo, "es el único IDE que necesito".
2.- Se diseño e implemento un Framework de AG para proveer toda la configuración que sobre el GA que necesitaba para testear el enfoque.
3.- Se utilizo MySQL como motor de base de datos para persistir toda la información de las tareas, recursos, costos, calidades, etc.
4.- Se modelaron los objetos relacionados al contexto del problema (Proyectos, tareas, recursos, etc.) en un proyecto aparte, y su persistencia si implemento con DAOs a mano... mala decisión, estoy trabajando en realizarlo mediante Hibernate en la actualidad, porque estoy probando ese Framework en mis ratos libres 8-| (sí, soy un tecla)…
5.- Luego tenia este otro proyecto en el que implementaba los hooks del AG para el dominio en particular, en donde se juntaban los puntos 1 y 4, y se implementaban las funciones de fitness, los cromosomas, los operadores genéticos, etc...
6.- Por ultimo una aplicación de escritorio en SWING para probar si todo lo anterior andaba realmente, la misma permitía crear proyectos (o importarlos de la PSPLIB) - la información respecto a desempeños, costos, etc. se plantaba de forma aleatoria en la base de datos - configurar el AG a gusto y placer, y correrlo para lograr al final planes de proyectos alternativos que en verdad sean buenos...
Hasta aquí todo fantástico, resulta que mi proceso de desarrollo era una enorme cascada, y había dejado el testing para la ultimo (como todo proyecto de la facultad :P)...
/** Importante */
Lo que queda implícito en lo contado anteriormente y que es lo que realmente importa, es que la aplicación realiza un gran número de consultas a la base de datos para obtener "calidades de desempeños", "costos de realización", etc al momento de evaluar el fitness de un cromosoma (posible plan de proyecto), y dado que de manejan poblaciones de muchos cromosomas, y se itera en el proceso de evolución muchas veces hasta encontrar planes que valgan la pena, ya se imaginaran la cantidad de accesos a la base de datos...
Muy bien, llego la hora de probar la aplicación y ver lo maravilloso del código escrito (al menos eso pensé de forma muy inocente), al principio, luego de solucionar un par de bugs menores, todo parecía andar bien, el programa respondía de forma correcta para proyectos pequeños... pero el objetivo era que anduviera con proyectos más grandes, así que empecé a probar con los de la PSPLIB.... y como era de esperarse, algo fallo...
El problema era un terrible desbordamiento de memoria de la maquina virtual, mi primer solución fue aumentarle la memoria (-Xmm...), el resultado fue que tardo un poco más en quedarse sin memoria :P...
Luego de inútiles esfuerzos por debugear la monstruosa aplicación, y sin ganas de realizar unidades de testeo para cada proyecto por separado... y por supuesto, convencido que mi código era una obra maestra, pero sin aun entender por qué se quedaba sin memoria al intentar correrlo... en ese momento de amargura (y furia), vi la luz (en realidad vi por casualidad el icono del “Profiler” en la barra de herramientas de mi querido NetBeans), habia leído de (en ese momento) el nuevo "chiche" para monitorear la memoria, cpu, etc de aplicaciones java, pero no lo había probado, y dije, es mi última esperanza (o tendría que abandonar el proyecto y rendir de forma regular los finales de las materias :-/ ).
Así que ahí estaba yo, “Profileando” mi proyecto... al principio pensé que iba a ser complicado (pero mejor que rendir examen :P), pero luego de unos minutos empiezas a ver cómo puedes visualizar un montón de de aspectos de la aplicación, de forma grafica... y ahí fue donde pude ver el grafico de memoria crecer hasta el desbordamiento :(... pero no me rendí, mi primera suposición fue que quizás estaría teniendo un problema con los cromosomas, que quedaran colgados en algún lugar tras cada iteración del algoritmo, inaccesibles para el Garbage Collector (si, apreté muchas veces el botón para correr el GC desde el Profiler :P)…
Pero inspeccionando en detalle las clases, me di cuenta que la cantidad de instancias de objetos cromosoma, se mantenía constante, como debía ser, en si todas las clases parecian estar dentro de los parámetros normales (de vuelta me volví a convencer que mi código era una obra maestra :P)...
Fue en ese momento que note que la mayor parte de la memoria consumida estaba en instancias de la clase String (y yo no realizaba trabajo intensivo sobre Strings)... en ese momento me empecé a darme cuenta de donde podía estar el problema, pero estaba cansado y me fui a dormir...
Al día siguiente me levante con la idea de que estaba realizando un loging en algún lado que se estaba saliendo de control.... pero mis logs no mostraban ninguna anomalía... fue entonces que me di cuenta que me faltaba un log por revisar, el de la conexión a la base de datos... y, luego de revisar el mismo, cuya salida no era la salida estándar, por eso no lo había visto antes, me di cuenta que una consulta SQL arrojaba una excepción cada vez que se ejecutaba, y se ejecutaba muuuuchas veces, y en cada oportunidad logueaba el error.... y este log crecía durante la vida del programa hasta dejarlo sin memoria...
En este punto debo admitir que como un “pelotas tristes” había dejado el bloque catch vacio... el único que no tenía tratamiento de error y fallaba... y si, era cantado...
En fin, luego de corregir el pequeño error (un comilla ' en lugar de una " en una consulta SQL), observe satisfactoriamente como todo andaba a las mil maravillas, y pude así entregar el proyecto...
Moralejas de esta historia:
* Nunca dejes un bloque catch vacio...
* Nunca uses un proceso de desarrollo en cascada para una aplicación mediana - grande...
* JDBC y DAOs a manopla pueden traerte dolores de cabeza...
* El Profiler (Java VisualVM) puede ser muy útil para inspeccionar el comportamiento de la aplicación en tiempo de ejecución...
* Combinar este último con unas horas de sueño puede ser muy productivo (o a caso nunca tuvieron un problema y soñaron la solución???)...
Bueno, esto fue todo amigos, espero no haberlos aburrido con mi relato...
carlitos.
Share
You need to be a member of Open Source University Meetup to add comments!
Join this social network