diff src/backend/utils/sort/tuplesort.c
index ce27e40..80ac11b
*** a/src/backend/utils/sort/tuplesort.c
--- b/src/backend/utils/sort/tuplesort.c
*************** tuplesort_end(Tuplesortstate *state)
*** 957,970 ****
   * Grow the memtuples[] array, if possible within our memory constraint.
   * Return TRUE if able to enlarge the array, FALSE if not.
   *
!  * At each increment we double the size of the array.  When we are short
!  * on memory we could consider smaller increases, but because availMem
!  * moves around with tuple addition/removal, this might result in thrashing.
!  * Small increases in the array size are likely to be pretty inefficient.
   */
  static bool
  grow_memtuples(Tuplesortstate *state)
  {
  	/*
  	 * We need to be sure that we do not cause LACKMEM to become true, else
  	 * the space management algorithm will go nuts.  We assume here that the
--- 957,974 ----
   * Grow the memtuples[] array, if possible within our memory constraint.
   * Return TRUE if able to enlarge the array, FALSE if not.
   *
!  * At each increment we double the size of the array.  When we are short on
!  * memory we do attempt one last, smaller increase.  This only happens at most
!  * once, since availMem moves around with tuple addition/removal. To do othewise
!  * might result in thrashing.  This is nothing more than a last-ditch effort to
!  * avoid exceeding allowedMem, an undesirable outcome if avoidable.
   */
  static bool
  grow_memtuples(Tuplesortstate *state)
  {
+ 	int			newmemtupsize;
+ 	long		memNowUsed = state->allowedMem - state->availMem;
+ 
  	/*
  	 * We need to be sure that we do not cause LACKMEM to become true, else
  	 * the space management algorithm will go nuts.  We assume here that the
*************** grow_memtuples(Tuplesortstate *state)
*** 974,991 ****
  	 * enough to force palloc to treat it as a separate chunk, so this
  	 * assumption should be good.  But let's check it.)
  	 */
! 	if (state->availMem <= (long) (state->memtupsize * sizeof(SortTuple)))
! 		return false;
  
  	/*
  	 * On a 64-bit machine, allowedMem could be high enough to get us into
  	 * trouble with MaxAllocSize, too.
  	 */
! 	if ((Size) (state->memtupsize * 2) >= MaxAllocSize / sizeof(SortTuple))
  		return false;
  
  	FREEMEM(state, GetMemoryChunkSpace(state->memtuples));
! 	state->memtupsize *= 2;
  	state->memtuples = (SortTuple *)
  		repalloc(state->memtuples,
  				 state->memtupsize * sizeof(SortTuple));
--- 978,1020 ----
  	 * enough to force palloc to treat it as a separate chunk, so this
  	 * assumption should be good.  But let's check it.)
  	 */
! 	if (memNowUsed > state->availMem)
! 	{
! 		int			memtupsize = state->memtupsize;
! 		long		allowedMem = state->allowedMem;
! 
! 		/*
! 		 * For this last increment, abandon doubling strategy.
! 		 *
! 		 * Use the known size (in bytes) of the tuples seen so far to estimate a
! 		 * memtuples size that is just within our constraint. This is nothing
! 		 * more than a heuristic.
! 		 *
! 		 * N.B. We rely on the assumption that nothing other than memtuples and
! 		 * individual tuple storage has been deducted from availMem.
! 		 */
! 		newmemtupsize = memtupsize * allowedMem / memNowUsed;
! 
! 		Assert(newmemtupsize <= state->memtupsize * 2);
! 
! 		/* This may not be our first time through */
! 		if (newmemtupsize <= memtupsize)
! 			return false;
! 	}
! 	else
! 	{
! 		newmemtupsize = state->memtupsize * 2;
! 	}
  
  	/*
  	 * On a 64-bit machine, allowedMem could be high enough to get us into
  	 * trouble with MaxAllocSize, too.
  	 */
! 	if ((Size) (newmemtupsize) >= MaxAllocSize / sizeof(SortTuple))
  		return false;
  
  	FREEMEM(state, GetMemoryChunkSpace(state->memtuples));
! 	state->memtupsize = newmemtupsize;
  	state->memtuples = (SortTuple *)
  		repalloc(state->memtuples,
  				 state->memtupsize * sizeof(SortTuple));
