Tus profesores están planteando un punto importante. Desafortunadamente, el uso del inglés es tal que no estoy absolutamente seguro de qué dijeron. Permítanme responder la pregunta en términos de programas que no son juguetes que tienen ciertas características de uso de memoria y con los que he trabajado personalmente.
Algunos programas se comportan bien. Asignan memoria en oleadas: muchas asignaciones pequeñas o medianas seguidas de muchas liberaciones, en ciclos repetidos. En estos programas, los asignadores de memoria típicos funcionan bastante bien. Se fusionan en bloques liberados y, al final de una onda, la mayor parte de la memoria libre está en grandes trozos contiguos. Estos programas son bastante raros.
La mayoría de los programas se comportan mal. Asignan y desasignan memoria de forma más o menos aleatoria, en una variedad de tamaños, desde muy pequeños hasta muy grandes, y retienen un alto uso de los bloques asignados. En estos programas, la capacidad para fusionar bloques es limitada y con el tiempo terminan con la memoria muy fragmentada y relativamente no contigua. Si el uso total de memoria excede aproximadamente 1,5 GB en un espacio de memoria de 32 bits, y hay asignaciones de (digamos) 10 MB o más, eventualmente una de las asignaciones grandes fallará. Estos programas son comunes.
Otros programas liberan poca o ninguna memoria, hasta que se detienen. Asignan memoria progresivamente mientras se ejecutan, liberando solo pequeñas cantidades y luego se detienen, momento en el que se libera toda la memoria. Un compilador es así. También lo es una máquina virtual. Por ejemplo, el tiempo de ejecución de .NET CLR, escrito en C ++, probablemente nunca libera memoria. ¿Por qué debería hacerlo?
Y esa es la respuesta final. En aquellos casos en los que el programa tiene un uso de memoria suficientemente pesado, administrar la memoria con malloc y free no es una respuesta suficiente al problema. A menos que tenga la suerte de estar lidiando con un programa que se comporta bien, deberá diseñar uno o más asignadores de memoria personalizados que preasignen grandes cantidades de memoria y luego realicen una subasignación según la estrategia que elija. No puede usar gratis en absoluto, excepto cuando el programa se detiene.
Sin saber exactamente lo que dijeron sus profesores, para programas de escala de producción verdaderamente probablemente saldría de su lado.
EDITAR
Intentaré responder algunas de las críticas. Obviamente, SO no es un buen lugar para publicaciones de este tipo. Para ser claro: tengo alrededor de 30 años de experiencia escribiendo este tipo de software, incluidos un par de compiladores. No tengo referencias académicas, solo mis propios moretones. No puedo evitar sentir que las críticas provienen de personas con una experiencia mucho más limitada y corta.
Repetiré mi mensaje clave: equilibrar malloc y free no es una solución suficiente para la asignación de memoria a gran escala en programas reales. Bloque de coalescencia es normal, y permite ganar tiempo, pero es que no lo suficiente. Necesita asignadores de memoria serios e inteligentes, que tienden a capturar la memoria en trozos (usando malloc o lo que sea) y rara vez se liberan. Este es probablemente el mensaje que los profesores de OP tenían en mente, que él entendió mal.