code: @VisibleForTesting
    ByteBuffer allocateMemory() {
      if (!Boolean.getBoolean(DISABLE_ALLOCATE_DIRECT_PROPERTY)) {
        for (int retries = 0; retries < MEMORY_ALLOCATION_ATTEMPTS; retries++) {
          int targetCapacity = getMemoryForSort(retries);
          try {
            return ByteBuffer.allocateDirect(targetCapacity);
          } catch (OutOfMemoryError e) {
            log.info("Failed to allocate direct memory for sort: " + targetCapacity
                + " retrying with a smaller buffer.");
          }
        }
      }
      Runtime runtime = Runtime.getRuntime();
      int targetCapacity = getMemoryForSort(MEMORY_ALLOCATION_ATTEMPTS);
      try {
        if (targetCapacity < runtime.freeMemory() + (runtime.maxMemory() - runtime.totalMemory())) {
          log.info("Using indirect memory allocation.");
          return ByteBuffer.allocate(targetCapacity);
        } else {
          log.info("Skipping indirect memory allocation.");
        }
      } catch (OutOfMemoryError e) {
        log.info("Failed to allocate non-direct memory for sort: " + targetCapacity + " giving up");
      }
      throw new RejectRequestException("Failed to allocate memory for sort after "
          + MEMORY_ALLOCATION_ATTEMPTS + " attempts. Giving up.");
    }
docs: This attempts to allocate as much memory as can be claimed for sorting. Ideally this should be
  as large as possible. However because there may be multiple requests occurring on the same
  instance, several attempts may be made to allocate a large portion.
  
  @throws RuntimeException If we cannot allocate after several attempts.