Any attempt to track the object’s lifetime is invasive enough to alter the result significantly.
That’s especially true for the AutoCloseable
variant, which may be subject to Escape Analysis in the best case, reducing the costs of allocation and deallocation close to zero. Any tracking approach implies creating a global reference which will hinder this optimization.
In practice, the exact time of deallocation is irrelevant for ordinary objects (i.e. those without a special finalize()
method). The memory of all unreachable objects will be reclaimed en bloc the next time the memory manager actually needs free memory. So for real life scenarios, there is no sense in trying to measure a single object in isolation.
If you want to measure the costs of allocation and deallocation in a noninvasive way that tries to be closer to a real application’s behavior, you may do the following:
- Limit the JVM’s heap memory to n
- Run a test program that allocates and abandons a significant number of the test instances, such, that their required amount of memory is orders of magnitude higher than the heap memory n.
- measure the total time needed to execute the test program and divide it by the number of objects it created
You know for sure that objects not fitting into the limited heap must have been reclaimed to make room for newer objects. Since this doesn’t apply to the last allocated objects, you know that you have a maximum error matching the number of objects fitting into n. When you followed the recipe and allocated large multiples of that number, you have a rather small error, especially when comparing the numbers reveals something like variant A needing ~12 ns per instance on average and variant B needing 550 ns (as already stated here, these numbers are clearly marked with “on my machine” and not meant to be reproducible exactly).
Depending on the test environment, you may even have to slow down the allocating thread for the variant with finalize()
, to allow the finalizer thread to catch up.
That’s a real life issue, when only relying on finalize()
, allocating too many resources in a loop can break the program.