diff --git a/api/maven-api-model/src/main/mdo/maven.mdo b/api/maven-api-model/src/main/mdo/maven.mdo
index b3f8478293dd..1ba9e93a1f1a 100644
--- a/api/maven-api-model/src/main/mdo/maven.mdo
+++ b/api/maven-api-model/src/main/mdo/maven.mdo
@@ -1354,7 +1354,7 @@
*/
public String getManagementKey() {
if (managementKey == null) {
- managementKey = getGroupId() + ":" + getArtifactId() + ":" + getType() + (getClassifier() != null ? ":" + getClassifier() : "");
+ managementKey = (getGroupId() + ":" + getArtifactId() + ":" + getType() + (getClassifier() != null ? ":" + getClassifier() : "")).intern();
}
return managementKey;
}
diff --git a/compat/maven-model/src/test/java/org/apache/maven/model/pom/PomMemoryAnalyzer.java b/compat/maven-model/src/test/java/org/apache/maven/model/pom/PomMemoryAnalyzer.java
new file mode 100644
index 000000000000..bea49c38170c
--- /dev/null
+++ b/compat/maven-model/src/test/java/org/apache/maven/model/pom/PomMemoryAnalyzer.java
@@ -0,0 +1,377 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.pom;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.model.Model;
+import org.apache.maven.model.v4.MavenStaxReader;
+
+/**
+ * A utility class that analyzes Maven POM files to identify memory usage patterns and potential memory optimizations.
+ * This analyzer focuses on identifying duplicate strings and their memory impact across different paths in the POM structure.
+ *
+ *
The analyzer processes POM files recursively, tracking string occurrences and their locations within the POM structure.
+ * It can identify areas where string deduplication could provide significant memory savings.
+ *
+ *
Usage example:
+ *
+ * PomMemoryAnalyzer analyzer = new PomMemoryAnalyzer();
+ * Model model = reader.read(Files.newInputStream(pomPath));
+ * analyzer.analyzePom(model);
+ * analyzer.printAnalysis();
+ *
+ *
+ *
The analysis output includes:
+ *
+ *
Total memory usage per POM path
+ *
Potential memory savings through string deduplication
+ *
Most frequent string values and their occurrence counts
+ *
Statistics grouped by POM element types
+ *
+ *
+ *
This tool is particularly useful for identifying memory optimization opportunities
+ * in large Maven multi-module projects where POM files may contain significant
+ * duplicate content.
+ */
+public class PomMemoryAnalyzer {
+ private final Map> pathStats = new HashMap<>();
+ private final Map globalStringFrequency = new HashMap<>();
+ private int totalPoms = 0;
+
+ public static void main(String[] args) throws Exception {
+ if (args.length < 1) {
+ System.out.println("Usage: PomMemoryAnalyzer ");
+ System.exit(1);
+ }
+
+ Path rootDir = Paths.get(args[0]);
+ PomMemoryAnalyzer analyzer = new PomMemoryAnalyzer();
+ MavenStaxReader reader = new MavenStaxReader();
+
+ // Find all pom.xml files, excluding those under src/ or target/
+ Files.walk(rootDir)
+ .filter(path -> path.getFileName().toString().equals("pom.xml"))
+ .filter(path -> !containsSrcOrTarget(path))
+ .forEach(pomPath -> {
+ try {
+ Model model = reader.read(Files.newInputStream(pomPath));
+ analyzer.analyzePom(model);
+ } catch (Exception e) {
+ System.err.println("Error processing " + pomPath + ": " + e.getMessage());
+ }
+ });
+
+ // Print analysis
+ analyzer.printAnalysis();
+ }
+
+ private static boolean containsSrcOrTarget(Path pomPath) {
+ Path parent = pomPath.getParent();
+ while (parent != null && parent.getFileName() != null) {
+ String dirName = parent.getFileName().toString();
+ if (dirName.equals("src") || dirName.equals("target")) {
+ return true;
+ }
+ parent = parent.getParent();
+ }
+ return false;
+ }
+
+ public void analyzePom(Model model) {
+ totalPoms++;
+ Set