Skip to content

Conversation

@vonlinee
Copy link
Contributor

In my project, most of select statement use resultType instead of resultMap, like below:

<select id="selectAuthors"  parameterType="int" resultType="org.apache.ibatis.domain.blog.Author">
  select * from author where id = #{id}
</select>

every single inline resultMap holds 6 empty unmodifiable collection , see ResultMap.java. i think it is unnecessary.

public class ResultMap {
  ....
  private List<ResultMapping> resultMappings;
  private List<ResultMapping> idResultMappings;
  private List<ResultMapping> constructorResultMappings;
  private List<ResultMapping> propertyResultMappings;
  private Set<String> mappedColumns;
  private Set<String> mappedProperties;
  .....
}

before this change, the memory usage of single resultmap is shown below:

image

with this optimization, it will be like below:

QQ20251211-212103

@coveralls
Copy link

Coverage Status

coverage: 87.396% (+0.01%) from 87.382%
when pulling 7cdf925 on vonlinee:inline-resultmap-optimization
into 2299e6d on mybatis:master.

@hazendaz
Copy link
Member

@vonlinee

The screenshots only show the size of reference fields on the owning object, which will not change regardless of whether the field points to a new collection, an empty singleton, or null.

To demonstrate actual memory savings, can you provide either:

a heap dump comparison showing reduced ArrayList / HashSet instance counts or retained size, or

JOL output illustrating eliminated per-instance collection objects for inline ResultMaps?

Without that, the PR doesn’t yet substantiate the claimed memory reduction, and it also introduces immutability assumptions that should be explicitly justified.

@harawata What are your thoughts here?

@vonlinee
Copy link
Contributor Author

vonlinee commented Dec 13, 2025

@hazendaz
Hi, appreciated for the reply. i wrote a test demo shown below: it will create 200 inline resultMaps by method createInlineResultMap1 or createInlineResultMap2.

import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.session.Configuration;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

public class InlineResultMapMemoryUsageDemo {

  static final Configuration configuration = new Configuration();

  public static ResultMap createInlineResultMap1() {
    return new ResultMap.Builder(configuration, "selectAuthors-Inline", Map.class,
      new ArrayList<>(), null).build();
  }

  public static ResultMap createInlineResultMap2() {
    return ResultMap.inline(configuration, "selectAuthors-Inline", Map.class);
  }

  public static List<ResultMap> createInlineResultMaps(int count, Supplier<ResultMap> supplier) {
    final ArrayList<ResultMap> resultMaps = new ArrayList<>();
    for (int i = 0; i < count; i++) {
      resultMaps.add(supplier.get());
    }
    return resultMaps;
  }

  public static void main(String[] args) throws InterruptedException {
    final int resultMapCount = 200;
    List<ResultMap> resultMaps = createInlineResultMaps(resultMapCount, InlineResultMapMemoryUsageDemo::createInlineResultMap1);
    // List<ResultMap> resultMaps = createInlineResultMaps(resultMapCount, InlineResultMapMemoryUsageDemo::createInlineResultMap2);
    TimeUnit.MINUTES.sleep(30); // to dump heap
  }
}

i run this demo with the two methods respectively, then dump the heap as file heapdump-1.hprof (createInlineResultMap1) and heapdump-2.hprof (createInlineResultMap2), then i compare heapdump-1.hprof with file heapdump-2.hprof using visualvm, and i get the result shown in the screenshot below:

image

please tell me if there is something wrong with my steps.

@vonlinee
Copy link
Contributor Author

vonlinee commented Dec 13, 2025

and it also introduces immutability assumptions that should be explicitly justified.

i think the immutability of these collections has partly already existed after the ResultMap is built with method org.apache.ibatis.mapping.ResultMap.Builder#build, except mappedProperties.

// lock down collections
resultMap.resultMappings = Collections.unmodifiableList(resultMap.resultMappings);
resultMap.idResultMappings = Collections.unmodifiableList(resultMap.idResultMappings);
resultMap.constructorResultMappings = Collections.unmodifiableList(resultMap.constructorResultMappings);
resultMap.propertyResultMappings = Collections.unmodifiableList(resultMap.propertyResultMappings);
resultMap.mappedColumns = Collections.unmodifiableSet(resultMap.mappedColumns);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants