Cork: Dynamic Memory Leak Detection for Garbage-Collected Languages £
Total Page:16
File Type:pdf, Size:1020Kb
Cork: Dynamic Memory Leak Detection for Garbage-Collected Languages £ Maria Jump and Kathryn S. McKinley Department of Computer Sciences, The University of Texas at Austin, Austin, Texas 78712, USA g fmjump,mckinley @cs.utexas.edu Abstract agement. For example, C and C++ memory-related errors include A memory leak in a garbage-collected program occurs when the (1) dangling pointers – dereferencing pointers to objects that the program inadvertently maintains references to objects that it no program previously freed, (2) lost pointers – losing all pointers to longer needs. Memory leaks cause systematic heap growth, de- objects that the program neglects to free, and (3) unnecessary ref- grading performance and resulting in program crashes after per- erences – keeping pointers to objects the program never uses again. haps days or weeks of execution. Prior approaches for detecting Garbage collection corrects the first two errors, but not the last. memory leaks rely on heap differencing or detailed object statis- Since garbage collection is conservative, it cannot detect or reclaim tics which store state proportional to the number of objects in the objects referred to by unnecessary references. Thus, a memory leak heap. These overheads preclude their use on the same processor for in a garbage-collected language occurs when a program maintains deployed long-running applications. references to objects that it no longer needs, preventing the garbage This paper introduces a dynamic heap-summarization technique collector from reclaiming space. In the best case, unnecessary ref- based on type that accurately identifies leaks, is space efficient erences degrade program performance by increasing memory re- (adding less than 1% to the heap), and is time efficient (adding 2.3% quirements and consequently collector workload. In the worst case, on average to total execution time). We implement this approach a growing data structure with unused parts will cause the program in Cork which utilizes dynamic type information and garbage col- to run out of memory and crash. Even if a growing data structure is lection to summarize the live objects in a type points-from graph not a true leak, application reliability and performance can suffer. (TPFG) whose nodes (types) and edges (references between types) In long-running applications, small leaks can take days or weeks to are annotated with volume. Cork compares TPFGs across multiple manifest. These bugs are notoriously difficult to find because the collections, identifies growing data structures, and computes a type allocation that finally exhausts memory is not necessarily related to slice for the user. Cork is accurate: it identifies systematic heap the source of the heap growth. growth with no false positives in 4 of 15 benchmarks we tested. Previous approaches for finding leaks use heap diagnosis tools Cork’s slice report enabled us (non-experts) to quickly eliminate that rely on a combination of heap differencing [10, 11, 20] and growing data structures in SPECjbb2000 and Eclipse, something allocation and/or fine-grain object tracking [7, 8, 9, 13, 19, 24, 25, their developers had not previously done. Cork is accurate, scal- 28, 29]. These techniques degrade performance by a factor of two able, and efficient enough to consider using online. or more, incur substantial memory overheads, rely on multiple ex- ecutions, and/or offload work to a separate processor. Additionally, Categories and Subject Descriptors D.2.5 [Software Engineer- they yield large amounts of low-level details about individual ob- ing]: Testing and Debugging—Debugging aids jects. These reports require a lot of time and expertise to interpret. General Terms Memory Leak Detection Thus, prior work lacks precision and efficiency. This paper introduces Cork, an accurate, scalable, online, and Keywords memory leaks, runtime analysis, dynamic, garbage low-overhead memory leak detection tool for typed garbage- collection collected languages. Cork uses a novel approach to summarize, 1. Introduction identify, and report data structures with systematic heap growth. We show that it provides both efficiency and precision. Cork pig- Memory-related bugs are a substantial source of errors, and are gybacks on full-heap garbage collections. As the collector scans the especially problematic for languages with explicit memory man- heap, Cork summarizes the dynamic object graph by type (class) £ This work is supported by NSF CCR-0311829, NSF ITR CCR-0085792, in a summary type points-from graph (TPFG). The nodes of the NSF CCF-0429859, NSF EIA-0303609, DARPA F33615-03-C-4106, graph represent the volume of live objects of each type. The edges DARPA NBCH30390004, Intel, IBM, and Microsoft. Any opinions, find- represent the points-from relationship between types weighted by ings and conclusions expressed herein are the authors’ and do not necessar- volume. At the end of each collection, the TPFG completely sum- ily reflect those of the sponsors. marizes the live-object points-from relationships in the heap. For space efficiency, Cork stores type nodes together with global type information block (TIB). The TIB, or equivalent, is a required implementation element for languages such as Java and Permission to make digital or hard copies of all or part of this work for personal or C# that instructs the compiler on how to generate correct code and classroom use is granted without fee provided that copies are not made or distributed instructs the garbage collector on how to scan objects. The num- for profit or commercial advantage and that copies bear this notice and the full citation ber of nodes in the TPFG scales with the type system. While the on the first page. To copy otherwise, to republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. number of edges between types are quadratic in theory, programs POPL ’07 January 17-19, 2007, Nice, France. implement simpler type relations in practice; we find that the edges Copyright c 2007 ACM [to be supplied]. $5.00. 1 void scanObject(TraceLocal trace, Type Symbol Size 2 ObjectReference object) { HashTable H 256 3 MMType type = ObjectModel.getObjectType(object); Queue N 256 4 type.incVolumeTraced(object); // added 5 if (!type.isDelegated()) { Queue B 256 6 int references = type.getReferences(object); Company C 64 7 for (int i = 0; i < references; i++) { People P 32 8 Address slot = type.getSlot(object, i); 9 type.pointsTo(object, slot); // added (a) Object statistics 10 trace.traceObjectLocation(slot); 11 }} else { 12 Scanning.scanObject(trace, object); 13 }} H 1 Figure 2. Object Scanning C P P C P P C 1 1 2 2 3 4 3 to the user along with the data structure which contains them and the allocation sites that generate them. For clarity of exposition, we describe Cork in the context of a full-heap collector using an example program whose types are defined in Figure 1(a). B 1 N 1 2.1 Building the Type Points-From Graph (b) Object points-to graph To detect growth, Cork summarizes the heap in a type points- from graph (TPFG) annotated with instance and reference volumes. The TPFG consists of type nodes and reference edges. The type C|B:128 C:192 B:256 nodes represent the total volume of objects of type t (Vt ). The C|H:192 C|N:64 reference edges are directed edges from type node t ¼ to type node H:256 t and represent the volume of objects of type t ¼ that are referred P|H:128 to by objects of type t (V ¼ ). To minimize the costs associated t jt P:128P|N:64 N:256 with building the TPFG, Cork piggybacks its construction on the scanning phase of garbage collection which detects live objects by starting with the roots (statics, stacks, and registers) and performing (c) Type points-from graph a transitive closure through all the live object references in the heap. For each reachable (live) object o visited, Cork determines Figure 1. The type points-from graph summarizes the object the object’s type t and increments the corresponding type node by points-to graph the object’s size. Then for each reference from o to object o¼ , it ¼ increments the reference edge from t ¼ to t by the size of o . At the end of the collection, the TPFG completely summarizes the volume are linear in the number of types. The TPFG never adds more than of all types and references that are live at the time of the collection. 0.5% to heap memory. Figure 1(b) shows an object points-to graph (i.e., the heap it- Cork stores and compares TPGFs from multiple collections to self). Each vertex represents a different object in the heap and each detect and report a dynamic type slice with systematic heap growth. arrow represents a reference between two objects. Figure 2 shows We store points-from instead of points-to information to efficiently the modified scanning code from MMTk in Jikes RVM: Cork re- compute the candidate type slice. We demonstrate that the construc- quires two simple additions that appear as lines 4 and 9. Assume tion and comparison of TPFGs across multiple collections adds on scanObject is processing an object of type B that refers to an ob- average 2.3% to total time to a system with a generational collector. ject of type C (from Figure 1(b)). It takes the tracing routine and We apply Cork to 14 popular benchmarks from DaCapo object as parameters and finds the object type. Line 4 increments b.050224 [5] and SPECjvm [26, 27] benchmark suites. Cork the volume of type B (VB) in the node for this instance. Since the identifies and reports unbounded heap growth in three of them. We collector scans (detects liveness of) an object only once, Cork in- confirm no additional memory leaks in the other 11 benchmarks crements the total volume of this type only once per object instance.