560 likes | 671 Views
JProbe Memory Debugger Tips and Tricks. Leonard Slipp Quest Software. Goals of Our Session. Preparing Your Investigation Object Cycling Analysis What it is and why it’s important Investigative Setup Interpreting Runtime Information Loitering Object (Memory Leak) Analysis
E N D
JProbe Memory Debugger Tips and Tricks Leonard Slipp Quest Software
Goals of Our Session • Preparing Your Investigation • Object Cycling Analysis • What it is and why it’s important • Investigative Setup • Interpreting Runtime Information • Loitering Object (Memory Leak) Analysis • What it is and why it’s important • Investigative Setup • Interpreting Runtime Information • Snapshot Analysis
Memory Safety in Java • Memory safety was a key aspect in the design of... • The Java Language • Absence of any form of pointer arithmetic • Can not directly reclaim object memory • And the Java Virtual Machine (JVM) • Bytecode instruction set • Runtime checks (array bounds, reference casts) • Garbage collection
Memory Safety in Java • Entire classes of memory-related problems were eliminated • Buffer overruns • De-referencing stale pointers • Memory leaks • However subtle memory management issues remain that can easily undermine the performance of your application • Object Cycling • Loitering Objects (Java’s “Memory Leaks”)
Tip: Adopt a Use Case-centric Investigative Approach • As an investigator, you want to be very comfortable with the user’s view of your application • Why Use Case-centric Investigation ? • Centers investigation on the user’s experience and how the symptoms of the underlying flaw affect them • Focus on the execution path of the use case, and how the underlying implementation is flawed
Our Example Application • A servlet-based J2EE application with a single use case: • Select a company on the application’s main page • Other applications… • Sign on • Search catalog • Add to virtual shopping cart • Go to the virtual check out • etc..
Our Example Application (Con’t) • Servlet invocation: • Reads the historical price information from an XML file • Reformats the data into an HTML table which is then returned to the browser and rendered
Tip: Ensure You’re Confident with the Underlying Architecture • You need to have a comfortable literacy with the internal architecture and design goals of the application • Names of all the packages • Names of key classes and methods • For each of the application use cases, ensure you are familiar with • The principle methods invoked along that execution path • Any attempts at “optimizations” (caching, pooling, etc :-) • If you’re not familiar with the underlying design and its implementation, the investigation will be much more difficult
Tip: Ensure You’re Confident with the Underlying Architecture • In our example program… • One Package • com.acme.* • Four Principle Classes/Interfaces • com.acme.StockServlet • com.acme.StockDataJDOM • com.acme.PageCache • com.acme.CachedPage • The program uses a Most Recently Used (MRU) caching algorithm that retains the last 3 most recently requested pages
Tip: Organize Your Workspace for Fluid Investigation • “Tile” the UI of your application along with the UI of JProbe so everything is visible • Eliminate the effort of constantly repositioning and resizing dialog boxes • Focus your attention on the investigation, not on repositioning dialogs JProbe UI Application UI
Object Cycling • One of the principal causes of performance loss in Java is the excessive creation of short life cycle objects • Performance loss is due to... • Memory allocation within the JVM heap • Object initialization via chain of constructor calls • Enhanced garbage collection activity • As a performance investigator, identify those methods in your application-level that are object cycling • They are your first candidates to examine for refactoring to improve performance
Object Cycling Analysis:Investigative Setup • Within the LaunchPad… • Enable Run Garbage Monitor During Use Case • Enter an asterisk (*) in the Filter on Package, Class or Method column of the first line in the Filter table • You want to see the entire heap contents Then press
Object Cycling Analysis:Runtime Information • Within the Runtime Heap Summary, before you select Start Use Case… • Select the Garbage Monitor tab, and… • Enter the fully qualified set of methods package.class.method to track allocations from • com.acme.*.* class package methods
Object Cycling Analysis:Runtime Information Within the Runtime Heap Summary, press Start Use Case Then, within your application’s UI, begin the use case • In this case, we’ll simply select a stock from the list
Object Cycling Analysis:Runtime Information • As GCs within the JVM occur, Garbage Monitor will indicate… • The type of objects reclaimed • The methods that they were allocated from • When the use case completes, press Finish Use Case e
Object Cycling Analysis:Runtime Information • When Finish Use Case is pressed, Garbage Monitor provides a final update to its table • Examine the top couple of lines in the table • The doGet() method in com.acme.StockServlet object cycles through 2,298 StringBuffers just to service 1 request !
What is a “Memory Leak” in Java ? • Memory leaks (as traditionally defined in C/C++) cannot occur in Java • That memory is reclaimed by the Garbage Collector • However, Java programs can still exhibit the macro-level symptoms of traditional memory leaks • Heap size seemingly grows without bounds • Occurs when objects that have outlived their usefulness to the application remain within the heap through successive garbage collections
JVM Runtime Data Areas Heap • Heap • The common memory pool where all objects and arrays are stored • Thread Stack(s) • One stack per thread of execution • Each stack consists of a series of method frames (one per called method) which contain the method arguments and return value, the local variables within the method and a bytecode operand stack for intermediate results • Method Area • Maintains the data structures for each loaded class in the JVM Thread Stack ... Thread Stack JVM Method Area (Java program and JVM) executing within the OS (Java program) executing within the JVM
Java Memory Management • As objects are created within a running Java program, they’re stored within the JVM’s heap • Central to Java’s memory management subsystem is the notion of garbage collection • Removes objects that are no longer needed • Undecidable in general, so Java uses an approximation... • Removes objects that are no longer reachable (accessible to the program at the beginning of a garbage collection cycle) • The reachability test starts at the heap’s root set
The Root Set • Set of foundational object references within your application • static reference fields within class definitions • Local reference variables within the method frames of each thread stack • The contents of the JVM’s root set changes dynamically • As threads enter and exit methods, local reference variables come into and go out of scope (enter and leave the root set)
Dynamic Nature of the Root Set - 1 1 public 2 class MyApp 3 { 4 static private MyAppmyApp = null; 5 6 static public 7 void 8 main( String[] args ) 9 { 10 myApp = new MyApp( ); 11 myApp.method1( ); 12 myApp.method2( ); 13 } Root Set: MyApp myApp String[] args
Dynamic Nature of the Root Set - 2 14 private void 15 method1( ) 16 { 17 FooObjectfooObj = new FooObject( ); 18 ... 19 } 20 21 private void 22 method2( ) 23 { 24 BarObjectbarObj = new BarObject( ); 25 ... 26 } 27 } Root Set: MyApp myApp String[] args FooObject fooObj
Dynamic Nature of the Root Set - 3 1 public 2 class MyApp 3 { 4 static private MyAppmyApp = null; 5 6 static public 7 void 8 main( String[] args ) 9 { 10 myApp = new MyApp( ); 11 myApp.method1( ); 12 myApp.method2( ); 13 } Root Set: MyApp myApp String[] args
Heap Root Set Reachable Objects • Elements within the root set directly refer to objects within the heap of the JVM • Reference variables within those objects refer to further objects within the Heap (indirectly reachable from the Root Set)
Reachable Objects & GC • At the beginning of a GC cycle, objects within the heap can be considered to be in one of two progressive “states”: • Allocated • Exists within the JVM’s heap • Reachable • A path exists (directly or indirectly) from a member of the root set, through a sequence of references, to that object
At the beginning of a GC cycle, objects that are allocated but no longer reachable are reclaimed by the Garbage Collector Reachable Objects & GC Allocated Reachable
What is a “Memory Leak” in Java? • Let’s extend the set of object states to three: • Allocated • Exists within the JVM’s heap • Reachable • A path exists (directly or indirectly) from a member of the root set, through a sequence of references, to that object • Live • From the intent of the application’s design, the program will use the object (meaning at least one of its public fields will be accessed and/or one of its public methods will be invoked) along some future path of execution
Memory leak in C/C++ (handled by JVM’s GC) “Memory leak” in Java What is a “Memory Leak” in Java? Allocated Reachable Live
Loitering Objects • The term “Memory Leak” has a lot of historical context from C/C++ and it doesn’t accurately describe the problem as it pertains to Java • New term: Loitering Object or Loiterer • An object that remains within the Heap past its useful life to the application • Arise from an invalid reference that makes the object reachable to the GC
Loitering Objects • Impact can be very severe • Rarely a single object, but an entire sub-graph of objects • A single lingering reference can have massive memory impact (and a significant performance impact) • Overall process requires more memory than necessary • JVM’s memory subsystem works harder • In the worst case, your Java application will throw an OutOfMemoryErrorand terminate Unintentional reference
Reference Management • The key to effective memory management in Java is effective reference management • What undermines effective reference management ? • Lack of awareness of the issue • Bad habits from C/C++ development • Class Libraries and Application Frameworks • Ill-defined reference management policies • Encapsulate flawed reference assignments • Tool (IDEs and others) generated software
Heap Investigation Strategy • You need a structured and disciplined approach to identify loitering objects systematically • Ensure that the underlying implementation adheres to the intent of your design • Based on classic scientific testing • Establish a hypothesis (what you expect to see) • Design and run an experiment to prove your hypothesis • Compare the experimental results against your hypothesis • Resolve the differences (if any)
Structure Your Hypothesis and Experiments Around Use Cases • Focus on the Use Case-centric approach • Your hypothesis consists of the set of objects you expect to persist at the end of your use case (which you know from your architectural design) • Use Memory Debugger’s Start Use Case and Finish Use Case features to define your use case
Loitering Object Analysis:Investigative Setup • Within the LaunchPad… • Disable Run Garbage Monitor During Use Case • Enter an asterisk (*) in the Filter on Package, Class or Method column of the first line in the Filter table • You want to see the entire heap contents Then press
Loitering Object Analysis:Runtime Information • Within the Runtime Heap Summary… • The Instance Summarytable (below the Heap Graph) provides a detailed breakdown of the Heap contents at the leading edge of the Heap Graph
Loitering Object Analysis:Runtime Information • When you press Start Use Case… • Two additional columns appear within the Instance Summary • Count Change • Memory Change • Use this information to gauge the net increate in objects as you exercise your use case
Loitering Object Analysis:Runtime Information • As you are testing your Use Case, filter the table to the classes within your implementation • Enter the fully qualified set of classes • com.acme.*
Loitering Object Analysis:Runtime Information • The design intent of our application is that the 3 MRU stock are cached (any older ones are disposed of) • Load 6 in sequence • Apple • Compaq • Dell • Gateway • Hewlett-Packard • IBM • Oh, No ! – All 6 are being cached (the oldest 3 are loitering)
Resolving Loitering Object Flaws • Loitering Objects represent either a design flaw or an implementation flaw within the application • How should applications be designed and implemented to avoid these flaws ? • Knowing how they can be avoided helps us investigate how they they arose in our application
Design for Reference Management • For each application-level use case, explicitly characterize: a. The life cycle of each object b. The inter-relationships (nature and duration) between various objects
Object Lifecycles • For each object required in your design to fulfill an application-level use case, you need to define: • Its point of creation • The duration of its usefulness • The point at which it should be eliminated from the runtime environment
Object Lifecycles • In Java, creating an object within the runtime environment is an explicit act, while its elimination is an implicit one • Defining – within your design – the point when your object should be eliminated will help you validate the correctness of your subsequent Java implementation
Inter-Object Relationships • Objects establish relationships with one another as they collaborate to accomplish their goals • Examples: • Composition (a has-a relationship) • Association (a uses-a relationship) • Relationship life cycles • Relationships are established, exist for a defined period of time and then are revoked • Relationships are based on Java references
Inter-Object Relationships • When designing methods that establish and revoke relationships, think “Symmetry” • If you define a method that establishes a relationship, ensure you define a method that revokes it • The Observer Pattern subject.addObserver( Observer ) subject.removeObserver( Observer )
Implementation • Loitering objects often arise from simple coding oversights or omissions • Forgot to null-ify a reference variable • Failure to remove an object from an internal list • Difficult to detect, except in catastrophic situations • The Java Runtime Environment doesn’t provide any insight
Reference Variable Scope • Three forms of reference variables: • Class-based: • Reference variables within a class definition that have a static attribute associated with them • Object-based: • Non static reference variables within a class definition • Method-based: • Reference variables defined within the scope of a method
Reference Variable Scope • Don’t be concerned about assignments to method-based reference variables within methods of short execution time • Be attentive of assignments to class-based and object-based reference variables, and method-based reference variables within methods of long execution times