解決 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 替換為我們最佳化後的類
如此,無論是程式碼、覆蓋率有無改動,每次合併都只會合併增量的部分,合併後的檔案大小基本不會發生太大改變。
相關文章
- [程式設計題] 膨脹的牛牛程式設計
- Oracle RAC 11204 CHM(cluster healthy monitor) 檔案無限膨脹.Oracle
- C++中泛型使用導致的膨脹問題C++泛型
- Synchronized鎖及其膨脹synchronized
- 表膨脹的查詢方法
- opencv 影像腐蝕、影像的膨脹OpenCV
- 膨脹的template class成員函式函式
- 解決 AS 3.1.0 版本 Logcat 合併多條日誌的問題GC
- web前端面試題:20道做完信心嫉妒膨脹的測試題Web前端面試題
- [java][鎖]java鎖的膨脹和優化Java優化
- synchronized的實現原理——鎖膨脹過程synchronized
- OpenCV (iOS)中的腐蝕和膨脹(9)OpenCViOS
- IDEA目錄合併在一起問題解決Idea
- 如何使用BFC清除CSS浮動以及解決margin合併的問題CSS
- Java無限迴圈問題Java
- 當「SPA」應用遇上了膨脹的專案
- opencv中的影象形態學——腐蝕膨脹OpenCV
- 無限debugger的解決----(一)
- 併發處理中的問題以及解決這些問題的併發模型模型
- 關於 API 合併的問題API
- 解決無法使用VI的問題
- 做完這20道前端面試題,你定會瞬間膨脹前端面試題
- 正視問題的存在和積極尋求途徑解決問題
- java併發筆記四之synchronized 鎖的膨脹過程(鎖的升級過程)深入剖析Java筆記synchronized
- 深究盒模型的margin合併問題模型
- 解決XML下無效字元的問題XML字元
- 解決Centos無法yum源的問題CentOS
- 解決寶塔皮膚無法訪問的問題?
- 關於網路硬體配置出現問題,無法上網問題的解決
- gmail無法訪問問題解決--FGWAI
- 用分散式鎖解決併發問題分散式
- python合併多個csv檔案需要注意的問題(合併多個列名問題)Python
- git合併丟失程式碼問題分析與解決(錯誤操作導致)Git
- 使用 LVM 將多個硬碟合併,解決 /home 目錄容量不足問題LVM硬碟
- 《RabbitMQ》| 解決訊息延遲和堆積問題MQ
- c++實現的一種程式碼膨脹變形殼C++
- 4步追蹤導致事務日誌膨脹的SQL命令SQL
- 深入分析synchronized原理和鎖膨脹過程(二)synchronized