public final void mergeSorted() {
      TableOfContents.Section[] sections = new TableOfContents.Section[dexes.length];
      Dex.Section[] dexSections = new Dex.Section[dexes.length];
      int[] offsets = new int[dexes.length];
      int[] indexes = new int[dexes.length];

      // values contains one value from each dex, sorted for fast retrieval of
      // the smallest value. The list associated with a value has the indexes
      // of the dexes that had that value.
      TreeMap<T, List<Integer>> values = new TreeMap<T, List<Integer>>();

      for (int i = 0; i < dexes.length; i++) {
        sections[i] = getSection(dexes[i].getTableOfContents());
        dexSections[i] = sections[i].exists() ? dexes[i].open(sections[i].off) : null;
        // Fill in values with the first value of each dex.
        offsets[i] = readIntoMap(dexSections[i], sections[i], indexMaps[i], indexes[i], values, i);
      }
      if (values.isEmpty()) {
        getSection(contentsOut).off = 0;
        getSection(contentsOut).size = 0;
        return;
      }
      getSection(contentsOut).off = out.getPosition();

      int outCount = 0;
      while (!values.isEmpty()) {
        Map.Entry<T, List<Integer>> first = values.pollFirstEntry();
        for (Integer dex : first.getValue()) {
          updateIndex(offsets[dex], indexMaps[dex], indexes[dex]++, outCount);
          // Fetch the next value of the dexes we just polled out
          offsets[dex] =
              readIntoMap(
                  dexSections[dex], sections[dex], indexMaps[dex], indexes[dex], values, dex);
        }
        write(first.getKey());
        outCount++;
      }

      getSection(contentsOut).size = outCount;
    }
Merges already-sorted sections, reading one value from each dex into memory at a time.
android/android_framework/dex-maker/src/main/java/com/android/dx/merge/DexMerger.java