@Override
    public long spill(long size, MemoryConsumer trigger) throws IOException {
        if (trigger != this) {
            if (readingIterator != null) {
                return readingIterator.spill();
            }
            return 0L; // this should throw exception
        }

        if (inMemSorter == null || inMemSorter.numRecords() <= 0) {
            return 0L;
        }

        logger.info("Thread {} spilling sort data of {} to disk ({} {} so far)",
                Thread.currentThread().getId(),
                Utils.bytesToString(getMemoryUsage()),
                spillWriters.size(),
                spillWriters.size() > 1 ? " times" : " time");

        // We only write out contents of the inMemSorter if it is not empty.
        if (inMemSorter.numRecords() > 0) {
            final UnsafeSorterSpillWriter spillWriter =
                    new UnsafeSorterSpillWriter(inMemSorter.numRecords());
            spillWriters.add(spillWriter);
            final UnsafeSorterIterator sortedRecords = inMemSorter.getSortedIterator();
            while (sortedRecords.hasNext()) {
                sortedRecords.loadNext();
                final Object baseObject = sortedRecords.getBaseObject();
                final long baseOffset = sortedRecords.getBaseOffset();
                final int recordLength = sortedRecords.getRecordLength();
                spillWriter.write(baseObject, baseOffset, recordLength, sortedRecords.getKeyPrefix());
            }
            spillWriter.close();

            inMemSorter.reset();
        }

        return freeMemory();
    }
Sort and spill the current records in response to memory pressure.
indexr-query-opt/src/main/java/org/apache/spark/util/collection/unsafe/sort/UnsafeExternalSorter.java