Depending the nature of your computation, you can get an "analytical estimate", e.g. " memory usage grows like n^2" for a given algorithm.
If you don't have this information, you can try to guess the nature of the relationship between memory usage and dimension or time resolution/range, or both. One way to achieve this is to run the code iteratively increasing the dimension (and/or any other relevant parameters) and plot/fit the memory usage.
When both fail, you can either overshoot the prealloc if possible and cut the extra at the end of the computation (which is generally fine for short-lived computations), and/or prealloc by block (in theory).
To illustrate the first situation, if you know that a vector resulting from an iterative computation should be filled with, say between 1e7 and 1e8 elements, you can prealloc for 1e8 or even 2e8 elements (to be sure) and reduce the vector to the actual number of elements after the computation (instead of iteratively increasing its size).
To illustrate the second situation, if you cannot overshoot the prealloc, you can perform an initial prealloc of e.g. 1e6 elements, and then extend it by 1e6 elements each time it is needed (or increase the size by a given factor, e.g 1.25, 1.5, 2, etc; see note 2). Doing so, you have n(extensions) << n(elements), which increases the efficiency in theory (see note 1).
Note 1: the extension by block is quite slow in MATLAB in practice, even slower than not preallocating (which is not what I get in other languages/contexts). I would be interested to have an explanation about that.
Note 2: I don't know what was the depth of your question, but if you were thinking about how the JIT optimizes memory management internally (e.g. 1.25 to 2 growth factor for realloc() operations, and not how to manage "preallocation" at a user level), you might want to contact Mathworks. I found some information about other languages here (and references therein):
but nothing about how it is done internally in MATLAB and whether it is worth caring about optimal growth factors (for reuse) at a user level.