解決 jacoco 合併體積無限膨脹的問題
背景
目前想每隔 10 分鐘自動收集一次測試環境所有特性分支的當前覆蓋率,並做合併操作,提高覆蓋率收集效率和準確性。
但實際在合併後覆蓋率的檔案會持續膨脹,如果頻繁合併會導致磁碟迅速變滿。
原因分析
分析 merge 邏輯
合併入口:
org.jacoco.core.tools.ExecFileLoader#save
實際寫入:
org.jacoco.core.data.ExecutionDataWriter#visitClassExecution
分析發現,當 append=true,則讀取原來的覆蓋率檔案,併合併到目標覆蓋率檔案中,所以檔案體積會一直變大。
解決辦法
在合併前,先讀取一次原來的檔案,提前做合併操作,待合併完後,不已追加寫的方式寫覆蓋率檔案,而是將覆蓋率重新寫入,這樣寫入的覆蓋率就是合併後的了。
新建一個類,繼承 ExecFileLoader,並覆蓋 save 方法
public void save(final File file, boolean append) throws IOException {
if (file.exists()) {
final FileInputStream in = new FileInputStream(file);
final ExecutionDataReader reader = new ExecutionDataReader(in);
// 1. 讀取目標覆蓋率檔案
ExecutionDataStore destExecDataStore = new ExecutionDataStore();
reader.setSessionInfoVisitor(new SessionInfoStore());
reader.setExecutionDataVisitor(destExecDataStore);
reader.read();
in.close();
// 2. 合併 新的覆蓋率檔案 和 目標覆蓋檔案
this.executionData.merge(destExecDataStore.getContents());
}
// 3. 不透過追加寫的方式寫入覆蓋率
final FileOutputStream fileStream = new FileOutputStream(file, false);
// Avoid concurrent writes from other processes:
fileStream.getChannel().lock();
final OutputStream bufferedStream = new BufferedOutputStream(
fileStream);
try {
save(bufferedStream);
} finally {
bufferedStream.close();
}
}
merge 方法:
public void merge(Collection<ExecutionData> executionDataList) {
Map<Long, ExecutionData> mergeEntries = new HashMap<Long, ExecutionData>();
// executionDataList 為待合入的覆蓋率檔案
for (ExecutionData executionData : executionDataList) {
mergeEntries.put(executionData.getId(), executionData);
}
//
for (Long id : mergeEntries.keySet()) {
// this.entries 是後續實際要寫入的覆蓋率資料
// 1. 如果類id一致,表示類沒有變動,則合併覆蓋率
if (this.entries.containsKey(id)) {
ExecutionData merge = mergeEntries.get(id);
ExecutionData entry = this.entries.get(id);
entry.mergeProbes(merge.getProbes());
this.entries.put(id, entry);
} else {
// 2. 如果不存在,則有可能類被改過,將舊的覆蓋率合併到新的
this.entries.put(id, mergeEntries.get(id));
}
}
}
mergeProbes 方法
public void mergeProbes(boolean[] probes) {
for (int i = 0; i < this.probes.length; i++) {
if (!this.probes[i] && probes[i]) {
this.probes[i] = probes[i];
}
}
}
最後,記得在 org.jacoco.cli.internal.commands.Merge 中,將 ExecFileLoader 替換為我們最佳化後的類
如此,無論是程式碼、覆蓋率有無改動,每次合併都只會合併增量的部分,合併後的檔案大小基本不會發生太大改變。
相關文章
- Synchronized鎖及其膨脹synchronized
- 表膨脹的查詢方法
- 解決 AS 3.1.0 版本 Logcat 合併多條日誌的問題GC
- IDEA目錄合併在一起問題解決Idea
- opencv 影像腐蝕、影像的膨脹OpenCV
- Jacoco 的萌新問題
- 無限debugger的解決----(一)
- ECI: 2021年媒體通貨膨脹報告
- 如何使用BFC清除CSS浮動以及解決margin合併的問題CSS
- 膨脹的template class成員函式函式
- 你是哪家的鎖,這麼膨脹
- web前端面試題:20道做完信心嫉妒膨脹的測試題Web前端面試題
- 解決無法使用VI的問題
- [java][鎖]java鎖的膨脹和優化Java優化
- synchronized的實現原理——鎖膨脹過程synchronized
- 解決codeblocks無法除錯的問題BloC除錯
- 解決Centos無法yum源的問題CentOS
- 當「SPA」應用遇上了膨脹的專案
- 專案範圍管理的最佳實踐:避免軟體專案膨脹
- 關於網路硬體配置出現問題,無法上網問題的解決
- 使用 LVM 將多個硬碟合併,解決 /home 目錄容量不足問題LVM硬碟
- 用分散式鎖解決併發問題分散式
- python合併多個csv檔案需要注意的問題(合併多個列名問題)Python
- 做完這20道前端面試題,你定會瞬間膨脹前端面試題
- 解決 raw.githubusercontent.com 無法訪問的問題Github
- 解決寶塔皮膚無法訪問的問題?
- 解決Visual Studio(2017)軟體無法重新生成問題
- 《RabbitMQ》| 解決訊息延遲和堆積問題MQ
- 解決ASM無法啟動問題ASM
- git合併丟失程式碼問題分析與解決(錯誤操作導致)Git
- mysql 高併發 select update 併發更新問題解決方案MySql
- 掌握Java的記憶體模型,你就是解決併發問題最靚的仔Java記憶體模型
- 使用go的併發性來解決Hilbert酒店問題Go
- PHP高併發商品秒殺問題的解決方案PHP
- java併發筆記四之synchronized 鎖的膨脹過程(鎖的升級過程)深入剖析Java筆記synchronized
- 資料編號+1 併發問題解決
- 合約 USDT 轉賬失敗的問題解決
- java併發程式設計 --併發問題的根源及主要解決方法Java程式設計