diff --git a/src/ProfileExplorerCore/Profile/Data/RawProfileData.cs b/src/ProfileExplorerCore/Profile/Data/RawProfileData.cs
index 8229ef04..bb8ee111 100644
--- a/src/ProfileExplorerCore/Profile/Data/RawProfileData.cs
+++ b/src/ProfileExplorerCore/Profile/Data/RawProfileData.cs
@@ -26,6 +26,15 @@ public class RawProfileData : IDisposable {
private static ProfileImage lastIpImage_;
[ThreadStatic]
private static IpToImageCache globalIpImageCache_;
+
+ ///
+ /// Clears thread-local caches on the current thread
+ ///
+ public static void ClearThreadLocalCaches() {
+ ipImageCache_ = null;
+ lastIpImage_ = null;
+ globalIpImageCache_ = null;
+ }
[ProtoMember(1)]
private List samples_;
[ProtoMember(2)]
diff --git a/src/ProfileExplorerCore/Profile/Data/ResolvedProfileStack.cs b/src/ProfileExplorerCore/Profile/Data/ResolvedProfileStack.cs
index aff87dc2..39ed2472 100644
--- a/src/ProfileExplorerCore/Profile/Data/ResolvedProfileStack.cs
+++ b/src/ProfileExplorerCore/Profile/Data/ResolvedProfileStack.cs
@@ -86,6 +86,16 @@ public sealed class ResolvedProfileStack {
public static ConcurrentDictionary frameInstances_ = new();
public static ConcurrentDictionary kernelFrameInstances_ = new();
+ ///
+ /// Clears all static frame caches. Must be called before processing a new trace
+ /// to prevent stale frame references from a previous session.
+ ///
+ public static void ResetCaches() {
+ uniqueFrames_.Clear();
+ frameInstances_.Clear();
+ kernelFrameInstances_.Clear();
+ }
+
public ResolvedProfileStack(int frameCount, ProfileContext context) {
StackFrames = new List(frameCount);
Context = context;
diff --git a/src/ProfileExplorerCore/Profile/ETW/ETWProfileDataProvider.cs b/src/ProfileExplorerCore/Profile/ETW/ETWProfileDataProvider.cs
index 575601cc..b46beebf 100644
--- a/src/ProfileExplorerCore/Profile/ETW/ETWProfileDataProvider.cs
+++ b/src/ProfileExplorerCore/Profile/ETW/ETWProfileDataProvider.cs
@@ -69,6 +69,10 @@ public ETWProfileDataProvider() {
for (int i = 0; i < imageLocks_.Length; i++) {
imageLocks_[i] = new object();
}
+
+ // Clear static caches from any previous trace load to prevent
+ // stale frame/function references leaking across sessions.
+ ResolvedProfileStack.ResetCaches();
}
public static async Task>
@@ -425,6 +429,12 @@ private void CollectChunkSamples(List(end - start + 1);
diff --git a/src/ProfileExplorerUI/MainWindowPanels.cs b/src/ProfileExplorerUI/MainWindowPanels.cs
index 17ad816c..4ee9144b 100644
--- a/src/ProfileExplorerUI/MainWindowPanels.cs
+++ b/src/ProfileExplorerUI/MainWindowPanels.cs
@@ -1032,10 +1032,13 @@ private async Task SetupSectionPanel() {
SectionPanel.CompilerInfo = compilerInfo_;
SectionPanel.Session = this;
+ // Clear stale module summaries from any previous session
+ // before adding the new ones.
+ SectionPanel.ClearModuleSummaries();
+
foreach (var doc in sessionState_.Documents) {
if (doc != sessionState_.MainDocument &&
doc != sessionState_.DiffDocument) {
- // Add optional modules, usually used for profiling.
SectionPanel.AddModuleSummary(doc.Summary);
}
}
diff --git a/src/ProfileExplorerUI/Panels/SectionPanel.xaml.cs b/src/ProfileExplorerUI/Panels/SectionPanel.xaml.cs
index a2de56f6..2d79d2e2 100644
--- a/src/ProfileExplorerUI/Panels/SectionPanel.xaml.cs
+++ b/src/ProfileExplorerUI/Panels/SectionPanel.xaml.cs
@@ -1252,6 +1252,11 @@ public void AddModuleSummary(IRTextSummary summary) {
}
}
+ public void ClearModuleSummaries() {
+ moduleSummaries_.Clear();
+ sectionExtensionComputed_ = false;
+ }
+
public bool HasSummary(IRTextSummary summary) {
return summary == summary_ ||
moduleSummaries_.Contains(summary);
diff --git a/src/ProfileExplorerUI/Panels/SectionPanelPair.xaml.cs b/src/ProfileExplorerUI/Panels/SectionPanelPair.xaml.cs
index e5ad93a1..26a3a5b2 100644
--- a/src/ProfileExplorerUI/Panels/SectionPanelPair.xaml.cs
+++ b/src/ProfileExplorerUI/Panels/SectionPanelPair.xaml.cs
@@ -151,6 +151,10 @@ public void AddModuleSummary(IRTextSummary summary) {
MainPanel.AddModuleSummary(summary);
}
+ public void ClearModuleSummaries() {
+ MainPanel.ClearModuleSummaries();
+ }
+
public async Task RefreshDocumentsDiffs() {
if (MainPanel.CurrentFunction == null) {
return;