import resource


def memory_fitness(threshold=2e9, maximum=3e9):
    """
    Returns a penalty for using too much memory.  Add this to your fitness
    function.  This measures the current processes maximum resident set (maxrss)
    which is the all time peak memory usage for the calling process.

    Argument threshold is where the this penalty begins.
    Argument maximum is where this penalty becomes an error (ValueError).

    Returns in the range [0, 1] where 0 is no penalty and 1 is the maximum
            memory usage.  Linear ramp from threshold to maximum.
    """
    rsc = resource.getrusage(resource.RUSAGE_SELF)
    size = rsc.ru_maxrss * 1024
    fit  = (size - threshold) / (maximum - threshold)
    if fit > 1 and False:
        # Don't raise an exception because this is measured after collecting all
        # of the data.  If there was a way to raise a OS exception when it tried
        # to allocate the memory...
        raise ValueError("Individual exceded memory limit (size %d bytes, maximum %d)."%(size, maximum))
    return max(0, fit)