- ALM used: GitHub
- CI system used: GitHub Actions
- Scanner command used when applicable:
sonarsource/sonarqube-scan-actionv6.0.0 - Languages of the repository: Go
- Error observed:
java.lang.OutOfMemoryError: Java heap space
We have a big Go repository that generates a huge coverage file (>3Gb). There are more than 3600 files in this repository. When the go plugin reads the coverage file it consumes more than 24 Gb of memory and crashes with java.lang.OutOfMemoryError: Java heap space.
We’ve tried splitting the coverage file in chunks to check if it’s able to read it this way but the same happens. Here is the log when it tries to read these multiple coverage chunks:
07:31:59.303 INFO Sensor Code Quality and Security for Go [go] (done) | time=9268ms
07:31:59.303 INFO Sensor Go Cover sensor for Go coverage [go]
07:31:59.625 INFO Load coverage report from '/home/runner/_work/<project>/coverage_split/coverage_00'
07:32:25.298 INFO Load coverage report from '/home/runner/_work/<project>/coverage_split/coverage_01'
07:32:50.993 INFO Load coverage report from '/home/runner/_work/<project>/coverage_split/coverage_02'
07:33:17.590 INFO Load coverage report from '/home/runner/_work/<project>/coverage_split/coverage_03'
07:33:44.163 INFO Load coverage report from '/home/runner/_work/<project>/coverage_split/coverage_04'
07:35:07.377 ERROR Error during SonarScanner Engine execution
java.lang.OutOfMemoryError: Java heap space
at java.base/java.util.Arrays.copyOfRange(Unknown Source)
at java.base/java.lang.StringLatin1.newString(Unknown Source)
at java.base/java.lang.String.substring(Unknown Source)
at java.base/java.util.Scanner.hasNextLine(Unknown Source)
at org.sonar.go.coverage.GoCoverSensor.parse(GoCoverSensor.java:195)
at org.sonar.go.coverage.GoCoverSensor.lambda$execute$1(GoCoverSensor.java:77)
at org.sonar.go.coverage.GoCoverSensor$$Lambda$992/0x00007f69f46aa450.accept(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(Unknown Source)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(Unknown Source)
at java.base/java.util.stream.ReferencePipeline$7$1.accept(Unknown Source)
at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.base/java.util.stream.ReferencePipeline.forEach(Unknown Source)
at org.sonar.go.coverage.GoCoverSensor.execute(GoCoverSensor.java:77)
at org.sonar.go.coverage.GoCoverSensor.execute(GoCoverSensor.java:71)
at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:68)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:75)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.lambda$execute$1(ModuleSensorsExecutor.java:48)
at org.sonar.scanner.sensor.ModuleSensorsExecutor$$Lambda$749/0x00007f69f45c9580.run(Unknown Source)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.withModuleStrategy(ModuleSensorsExecutor.java:66)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:48)
at org.sonar.scanner.scan.SpringModuleScanContainer.doAfterStart(SpringModuleScanContainer.java:66)
at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:200)
at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:179)
at org.sonar.scanner.scan.SpringProjectScanContainer.scan(SpringProjectScanContainer.java:216)
at org.sonar.scanner.scan.SpringProjectScanContainer.scanRecursively(SpringProjectScanContainer.java:212)
at org.sonar.scanner.scan.SpringProjectScanContainer.doAfterStart(SpringProjectScanContainer.java:175)
I’ve been checking the go plugin that reads the coverage file and it seems that it first parses all the coverage chunks, stores them in memory and then calls saveCoverage. Is it possible that this plugin writes each chunk file after it is parsed instead of having all the coverage in memory?
https://github.com/SonarSource/sonar-go/blob/master/sonar-go-plugin/src/main/java/org/sonar/go/coverage/GoCoverSensor.java:
void execute(SensorContext context, GoPathContext goContext) {
try {
Coverage coverage = new Coverage(goContext);
getReportPaths(context).forEach(reportPath -> parse(reportPath, coverage));
coverage.fileMap.forEach((filePath, coverageStats) -> {
try {
saveFileCoverage(context, filePath, coverageStats);
} catch (Exception e) {
LOG.warn("Failed saving coverage info for file: {}", filePath);
}
});
} catch (Exception e) {
LOG.warn("Coverage import failed: {}", e.getMessage(), e);
}
}
Thanks!