leakchecker: practical static memory leak detection for managed languages
DESCRIPTION
Static detection of memory leaks in a managed language such as Java is attractive because it does not rely on any leak-triggering inputs, allowing compile-time tools to find leaks before software is released. A long-standing issue that prevents practical static memory leak detection for Java is that it can be very expensive to statically determine object liveness in large applications. We present a novel (and the first practical) static leak detection technique that bypasses this problem by considering a common leak pattern. In many cases severe leaks occur in loops where, in each iteration, some objects created by the iteration are unnecessarily referenced by objects external to the loop. These unnecessary references are never used in later loop iterations. Based on this insight, we shift our focus from computing liveness, which is very difficult to achieve precisely and efficiently for large programs, to the easier goal of identifying objects that flow out of a loop but never flow back in. We formalize this analysis using a type and effect system and present its key properties. The analysis was implemented in a tool called LeakChecker and used to detect leaks in eight real-world programs, such as Eclipse, Derby, and log4j. LeakChecker not only identified known leaks, but also discovered new ones whose causes were unknown beforehand, while exhibiting a false positive rate suitable for practical use.TRANSCRIPT
LeakChecker: Prac,cal Sta,c Memory Leak Detec,on for Managed Languages
PRESTO: Program Analyses and So5ware Tools Research Group, Ohio State University
Dacong (Tony) Yan1, Guoqing Xu2, Shengqian Yang1, Atanas Rountev1
1 Ohio State University 2 University of California, Irvine
Memory Leaks in Managed Languages • Languages such as Java sMll have memory leaks: unnecessary references keep unused objects alive
• StaMc leak detecMon – Widely used for unmanaged languages such as C – Cannot be applied to managed languages: no explicit memory deallocaMon
• General definiMon of leaks – Precision: difficult to compute object liveness precisely – Performance: limited scalability for large programs
• Our approach – Shi5 the focus, and idenMfy common leak paVerns
2
Proposed Leak DetecMon for Java • ObservaMon: leaks are o5en related to frequently occurring events (e.g., loop iteraMons)
• SoluMon: focus on a user-‐specified event loop • ObservaMon: a leaking object is o5en
– created by one loop iteraMon – escapes this iteraMon – never used in later iteraMons
• SoluMon: interprocedural tracking of – whether an object escapes to a memory locaMon outside of the loop
– whether an escaping object flows from the outside locaMon back into a later loop iteraMon 3
Example
4
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } !
An example adapted from SPECjbb2000
Example
5
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } !
An example adapted from SPECjbb2000
Example
6
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } !
loop object
Example
7
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
outside object
loop object
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } !
Example
8
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
outside object
loop object
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } !
Example
9
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
outside object
loop object
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } !
Example
10
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } !
Example
11
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } !
Example
12
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } !
store16
Example
13
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } ! Order4 !
store16
escape
Transaction1 !
store16
Example
14
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } !
store24
Example
15
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } ! Order4 !
escape
Order[]23 ! Customer[]10 !Customer? ! Transaction1 !
store24
store24 store9 store22 store?
Example
16
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } ! Order4,i ! Transaction1 !
store16/prev
store24/orders, …, store9/custs
Example
17
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } ! Order4,i ! Transaction1 !
store24/orders, …, store9/custs leaking?
Example
18
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } ! Order4,i ! Transaction1 !
store16/prev leaking?
Example
19
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } ! Order4,i ! Transaction1 !
store16/prev leaking?
load11
Example
20
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } ! Order4,i ! Transaction1 !
store16/prev
load11
leaking?
store16
Example
21
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } ! Order4,i ! Transaction1 !
store16/prev
load11
leaking?
store16
load11/prev
Example
22
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } ! Order4,i ! Transaction1 !
store16/prev
load11
leaking?
store16
load11/prev (i+1)-‐th itera,on
i-‐th itera,on
Example
23
“main”: ! 1 Transaction t = new Transaction(); ! 2 for (int i = 0; i < X; ++i) { ! 3 t.display(); ! 4 Order order = new Order(...); ! 5 t.process(order); ! 6 } !!
7 class Transaction { ! 8 Order prev; ! 9 Customer[] custs = new Customer[…]; !10 void display() { !11 Order r = this.prev; !12 … // display r !13 this.prev = null; // remove !14 } !15 void process(Order p) { !16 this.prev = p; !17 Customer c = this.custs[…]; !18 c.addOrder(p); !19 ... // process p !20 } } !!!
21 class Customer { !22 Order[] orders = new Order[…]; !23 void addOrder(Order q) { !24 this.orders[...] = q; !25 } !26 } ! Order4,i ! Transaction1 !
store16/prev
store24/orders, …, store9/custs leaking
non-‐leaking
StaMc Analysis Outline • Object: pair of allocaMon site and calling context • Flows-‐out path
– Loop object escaping to outside object – Sequence of store statements for the flow
• Flows-‐in path – Escaping object flows from outside object into the loop – Sequence of load statements causing the flow
• Loop iteraMon constraints – Flows-‐in valid only if the corresponding Flows-‐out occurs in an earlier iteraMon
• On-‐demand analysis using context-‐free language reachability to match store/load and call/return
24
StaMc Analysis Outline • Object: pair of allocaMon site and calling context • Flows-‐out path
– Loop object escaping to outside object – Sequence of store statements for the flow
• Flows-‐in path – Escaping object flows from outside object into the loop – Sequence of load statements causing the flow
• Loop iteraMon constraints – Flows-‐in valid only if the corresponding Flows-‐out occurs in an earlier iteraMon
• On-‐demand analysis using context-‐free language reachability to match store/load and call/return
25
StaMc Analysis Outline • Object: pair of allocaMon site and calling context • Flows-‐out path
– Loop object escaping to outside object – Sequence of store statements for the flow
• Flows-‐in path – Escaping object flows from outside object into the loop – Sequence of load statements causing the flow
• Loop iteraMon constraints – Flows-‐in valid only if the corresponding Flows-‐out occurs in an earlier iteraMon
• On-‐demand analysis using context-‐free language reachability to match store/load and call/return
26
Order4 ! Order[]23 ! Customer[]10 !Customer? ! Transaction1 !store24 store9 store22 store?
StaMc Analysis Outline • Object: pair of allocaMon site and calling context • Flows-‐out path
– Loop object escaping to outside object – Sequence of store statements for the flow
• Flows-‐in path – Escaping object flows from outside object into the loop – Sequence of load statements causing the flow
• Loop iteraMon constraints – Flows-‐in valid only if the corresponding Flows-‐out occurs in an earlier iteraMon
• On-‐demand analysis using context-‐free language reachability to match store/load and call/return
27
StaMc Analysis Outline • Object: pair of allocaMon site and calling context • Flows-‐out path
– Loop object escaping to outside object – Sequence of store statements for the flow
• Flows-‐in path – Escaping object flows from outside object into the loop – Sequence of load statements causing the flow
• Loop iteraMon constraints – Flows-‐in valid only if the corresponding Flows-‐out occurs in an earlier iteraMon
• On-‐demand analysis using context-‐free language reachability to match store/load and call/return
28
Transaction1 !load11/prev
Order4,i-1 !
StaMc Analysis Outline • Object: pair of allocaMon site and calling context • Flows-‐out path
– Loop object escaping to outside object – Sequence of store statements for the flow
• Flows-‐in path – Escaping object flows from outside object into the loop – Sequence of load statements causing the flow
• Loop iteraMon constraints – Flows-‐in valid only if the corresponding Flows-‐out occurs in an earlier iteraMon
• On-‐demand analysis using context-‐free language reachability to match store/load and call/return
29
StaMc Analysis Outline • Object: pair of allocaMon site and calling context • Flows-‐out path
– Loop object escaping to outside object – Sequence of store statements for the flow
• Flows-‐in path – Escaping object flows from outside object into the loop – Sequence of load statements causing the flow
• Loop iteraMon constraints – Flows-‐in valid only if the corresponding Flows-‐out occurs in an earlier iteraMon
• On-‐demand analysis using context-‐free language reachability to match store/load and call/return
30
Transaction1 !outside object
StaMc Analysis Outline • Object: pair of allocaMon site and calling context • Flows-‐out path
– Loop object escaping to outside object – Sequence of store statements for the flow
• Flows-‐in path – Escaping object flows from outside object into the loop – Sequence of load statements causing the flow
• Loop iteraMon constraints – Flows-‐in valid only if the corresponding Flows-‐out occurs in an earlier iteraMon
• On-‐demand analysis using context-‐free language reachability to match store/load and call/return
31
Transaction1 !Order4,i !i-‐th itera,on
outside object
StaMc Analysis Outline • Object: pair of allocaMon site and calling context • Flows-‐out path
– Loop object escaping to outside object – Sequence of store statements for the flow
• Flows-‐in path – Escaping object flows from outside object into the loop – Sequence of load statements causing the flow
• Loop iteraMon constraints – Flows-‐in valid only if the corresponding Flows-‐out occurs in an earlier iteraMon
• On-‐demand analysis using context-‐free language reachability to match store/load and call/return
32
Transaction1 !Order4,i !store16/prev i-‐th itera,on
outside object
StaMc Analysis Outline • Object: pair of allocaMon site and calling context • Flows-‐out path
– Loop object escaping to outside object – Sequence of store statements for the flow
• Flows-‐in path – Escaping object flows from outside object into the loop – Sequence of load statements causing the flow
• Loop iteraMon constraints – Flows-‐in valid only if the corresponding Flows-‐out occurs in an earlier iteraMon
• On-‐demand analysis using context-‐free language reachability to match store/load and call/return
33
Transaction1 !(i+1)-‐th itera,on
Order4,i !store16/prev
load11/prev
i-‐th itera,on
outside object
StaMc Analysis Outline • Object: pair of allocaMon site and calling context • Flows-‐out path
– Loop object escaping to outside object – Sequence of store statements for the flow
• Flows-‐in path – Escaping object flows from outside object into the loop – Sequence of load statements causing the flow
• Loop iteraMon constraints – Flows-‐in valid only if the corresponding Flows-‐out occurs in an earlier iteraMon
• On-‐demand analysis using context-‐free language reachability to match store/load and call/return
34
– Captured by extended recency abstracMon (ERA)
StaMc Analysis Outline (cont.) • On-‐demand analysis
– Detect leaks only for objects allocated in specified loops – Context-‐free language reachability to match relevant store/load and call/return
• ConservaMve handling of thread lifeMme – Assume the lifeMme of each thread exceeds the loop lifeMme – Capture objects leaking to long-‐running threads
35
Analysis ImplementaMon • Memory leak
– An object leaks if it starts a flows-‐out path, but does not have a matching flows-‐in path
• ReporMng leaks – Leaking object, with calling context of its allocaMon – Outside target object, with calling context of its allocaMon – Escape-‐causing heap write (store) statement, with its calling context
• LeakChecker: leak detecMon tool built using Soot
36
EvaluaMon • 8 real-‐world Java programs
– Enterprise trading, so5ware tools, databases, logging – 3 programs never studied by exisMng work
• EffecMve for leak detecMon? – LeakChecker detected both known and new leaks
• Suitable for pracMcal use? – Analysis running Mme (all < 35 mins) – Reasonable false posiMve rate (avg < 50%)
• Case studies – Performed to understand quality of leak report – For each leak defect, pinpoint root cause and fix the problem in < 2 hours 37
Eclipse Diff • Scenario: compare two large JAR files
– runCompare method in compare plugin !– An arMficial loop to invoke runCompare mulMple Mmes
• Loop objects – Editor: display comparison results – HistoryEntry: represent list of opened editors, and allow users to navigate them backward/forward
• Outside object – History: managed by another plugin to save HistoryEntry
38
Editor ! History !HistoryEntry!compare plugin history plugin
!!!!
loop objects outside object
Conclusions • LeakChecker is both effecMve and pracMcal • Key insights
– Capture common paVerns of leaking behavior – Focus on user-‐specified event loops – Report leaks with detailed context informaMon
39
Thank you
40