Tengo una función Java cuya documentación afirma que no realiza asignaciones de memoria en montón.
¿Cómo puedo verificar si (todavía) se comporta como se afirma, en tiempo de ejecución?
Idealmente, me gustaría hacer esto durante una ejecución normal del programa (de producción), de una manera que el programa pueda analizar y mostrar como salida del programa.
Espero una API de tiempo de ejecución sólida simple como:
Si eso no es posible, me gustaría al menos poder hacer el equivalente durante algún tipo de ejecución de modo de depuración/perfilado.
Principalmente estoy interesado en hacer esto en tiempo de ejecución, pero si es posible hacerlo usando herramientas de análisis estático, también estaría interesado en eso.
He buscado en la web y no he encontrado nada. Hay generadores de perfiles de memoria, por ejemplo, JFR que pueden hacer cosas como informar y desglosar el uso actual del montón en un momento dado, pero no he visto ninguna evidencia de que puedan responder a este simple y preciso sí o no "¿ocurrió alguna asignación en este hilo durante este intervalo" consulta.
Puede hacer esto totalmente con la instrumentación de tiempo de ejecución. Es posible que no pueda hacerlo para una parte aislada de su programa, pero puede configurar algo como https://github.com/google/allocation-instrumenter para una ejecución aislada de su programa (o una muestra de ejecuciones en producción). Podrías usarlo, por ejemplo, así:
public class Test { public static void main(String [] args) throws Exception { AtomicInteger allocations = new AtomicInteger(); AllocationRecorder.addSampler(new Sampler() { public void sampleAllocation(int count, String desc, Object newObj, long size) { allocations.getAndIncrement(); } }); codeBlock(); // do any initialization, classloading first! int expectedAllocations = allocations.get(); codeBlock(); assert allocations.get() == expectedAllocations; // no more allocations } }Puede perfilar el uso de la memoria en un entorno controlado usando Runtime#freeMemory() , deshabilitando GC ( -XX:+UseEpsilonGC ) y ejecutando solo la lógica para probar.
// Logic to test (to load classes, do one-off initializations) Runtime runtime = Runtime.getRuntime(); long start = runtime.freeMemory(); // Logic to test long end = runtime.freeMemory(); assert start == end;No creo que haya otra manera de probar esto que no sea buscar instancias de new en el método y cualquier método al que llame.
Pruebas de asignación de memoria: es imposible aislar los efectos del método.
Evaluación comparativa: puede probar simplemente ejecutando el método de forma aislada, pero eso fallará en el caso de que las asignaciones en producción se realicen condicionalmente en función de la presencia de otros recursos, como
if (MyOtherClass.myOtherVariable != null) { int[] arr = new int[100]; }En este caso, la asignación de memoria está condicionada a algún otro paso que puede haber ocurrido o no.