eclipse-platform / eclipse-platform/eclipse.platform

`Path` object creation and operations dominate CPU time on large resource trees

Open
#2,568 1 comment 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Java
Stars
165
Forks
174
Avg merge
2d 8h
Merged PRs (30d)
22

Description

During analysis of two heapdumps shared [here](https://github.com/eclipse-pde/eclipse.pde/pull/2253#issuecomment-4054961583) the following issue was discovered as a hotspot that can benefit from optimization:

### Performance Data

| Metric | WITH transitive | WITHOUT transitive | Ratio |
|--------|----------------:|-------------------:|------:|
| Path.<init>() (µs) | 24,933,686 | 12,598,757 | **2.0×** |
| Path.computeSegmentCount() (µs) | 12,651,521 | 3,382,879 | **3.7×** |
| Path.append() (µs) | 14,264,596 | 5,157,314 | **2.8×** |
| Path.equals() (µs) | 6,327,370 | 1,207,964 | **5.2×** |
| StringLatin1.replace() (µs) | 32,550,291 | 9,422,718 | **3.5×** |

### Description

`Path` objects are created extensively throughout the JDT and Platform. The constructor calls `backslashToForward()` (which calls `String.replace('\\', '/')` — accounting for the `StringLatin1.replace()` overhead) and `computeSegmentCount()` (which scans the entire path string). The `equals()` method compares segments array-by-array.

With transitive dependencies, the number of classpath entries, package fragment roots, and resource lookups increases substantially, causing proportionally more `Path` creation and comparison. The **3.5× increase in `StringLatin1.replace()`** (32.5 seconds total!) is particularly notable — this is pure overhead from the `backslashToForward()` conversion that happens in every `Path` constructor, even on Linux where no backslashes exist.

### Suggested Fix

1. **Skip backslash conversion on non-Windows platforms**: `Path(String)` unconditionally calls `backslashToForward()` which does `path.replace('\\', '/')`. Since this build is running on a specific OS, the conversion could be skipped when `File.separatorChar == '/'`. *(Note: The source already has a `forWindows` parameter in the internal constructor, but the public `Path(String)` uses `Constants.RUNNING_ON_WINDOWS`. Verify this is correctly set.)*
2. **Intern or cache frequently used paths**: Classpath entry paths, project paths, and source folder paths are created repeatedly. An interning mechanism or flyweight pattern would reduce object creation.
3. **Lazy segment computation**: `computeSegments()` and `computeSegmentCount()` are called in the constructor. If many `Path` objects are created only for equality checks or `toString()`, lazy computation would save work.
4. **Use `IPath.of()` factory method**: If a canonical `IPath.of()` exists (or should be added), it could return cached instances for common paths.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.