Beruflich Dokumente
Kultur Dokumente
Table of Contents
Discovering Performance Bottlenecks.................................................................................................... 2 Profiled Application ................................................................................................................. 2 Discovering Performance Bottlenecks .................................................................................... 2 Memory Optimization .............................................................................................................................. 4 Profiled Application ................................................................................................................. 4 Memory Optimization .............................................................................................................. 4 Memory Optimization Using Allocation Tracking and Object Lifetime Profiling .................................... 8 Profiled Application ................................................................................................................. 8 Memory Optimization .............................................................................................................. 8 Discovering Memory Leaks................................................................................................................... 12 Profiled Application ................................................................................................................12 Discovering Memory Leaks................................................................................................... 12 Finding Memory Leak Candidates ........................................................................................ 15 Deadlock Detection ............................................................................................................................... 19 Profiled Application ............................................................................................................... 19 Detecting Deadlocks ............................................................................................................. 19 Profiling J2EE Applications ................................................................................................................... 21 Profiled Application ............................................................................................................... 21 Prerequisites ......................................................................................................................... 21 Profiling J2EE Application ..................................................................................................... 21
PAGE 2
The method that consumed the greatest amount of CPU time is the method remove in the class java.util.ArrayList. This method is being invoked every time we need to remove a point because we chose to use an ArrayList to store the collection of points we are working with. While we cannot change the implementation of remove, we should still try to understand why so much of the time is being spent in it. There are two possible reasons, both of which are true in this case. The first reason is the number of times its being invoked. If we assume a random distribution of points, then about 50% of them should be getting removed. Thats around 50,000 invocations of the remove method. The second reason is the amount of time spent in remove each time its called. A list is a good choice of data structure when the number of elements is relatively small or when you dont need to search it, but the remove method needs to search the list to find the index of the element to be removed every time it is invoked. It does so using a linear search, which is fairly slow when there are between 100,000 and 50,000 items in the list. There are two possible solutions. The first is to change the algorithm so that we dont need to remove points from the list, possibly by creating a second list and adding the points were keeping to it. The second solution is to use a data structure from which the points can be removed in less time. Well choose the second solution because it requires fewer changes to the existing code. 6. Change the type of collection from ArrayList to HashSet (see the comparison of files PointSystem.java in the projects com.instantiations.sample.bottleneck and com.instantiations.sample.bottleneck.solved). 7. Profile the changed application. 8. Note that the execution time is less than 1 second, which is much more reasonable.
PAGE 3
Memory Optimization
Profiled Application
Profiled application: ThingsTest Project: com.instantiations.sample.memory Description: The application generates 50,000 instances of the class Thing (things have a name, a value, and a collection of named properties) and sets the property Broken to true for approximately 5% of the created things. It doesnt set any properties on the other things. The type of collection of things is ArrayList. The type of the field properties is HashMap.
Memory Optimization
1. Launch the application in the profile mode. 2. Watch the Memory Telemetry view.
The amount of used heap memory is more than 8 MB, which is too much for this application. 3. Take a memory snapshot and open it. 4. Look at the Biggest Objects view.
PAGE 4
The biggest object which can interest us is an instance of java.util.ArrayList. 5. Use java.util.ArrayList as a name filter and open the Class List view.
Both the shallow size of class java.util.ArrayList and the number of instances are small compared to the retained size, which tells us that the list is probably not the problem, its more likely the elements stored in the list that are using too much memory. To confirm this, lets look at the problem from a different angle. 6. Select the Class List view and sort the classes by Shallow Size.
PAGE 5
The class with the biggest shallow size is java.util.HashMap. It is also the class with the biggest number of instances and one of the largest retained sizes. The number of instances of the class java.util.HashMap is near 50,000. The number of objects of the class java.util.HashMap$Entry is near 2,500. Because there are fewer entries than there are hash maps, it tells us that most of the hash maps must be empty (at least 47,500 of them). There is another class with almost as many instances: the class Thing. 7. Look at the implementation of the class Thing. We can see two interesting facts. First, every instance has a field named properties of type HashMap. Second, this field is initialized to an instance of HashMap when the instance of Thing is created. We know from the problem description that we are only setting the value of a property on about 5% of the instances of Thing. This suggests that a possible solution would be to leave the field properties un-initialized until we first set a property, treating a value of null as being equivalent to any empty HashMap. 8. Change the code to initialize the field property only if a property is set on the thing (see the comparison of files Thing.java in the projects com.instantiations.sample.memory and com.instantiations.sample.memory.solved). 9. Profile the changed application. 10. Take a memory snapshot and open it. 11. Look at the Class List view. Use java.util.HashMap as name filter.
PAGE 6
The number of object of class java.util.HashMap is near 2,500, which is what we would have expected. 12. Look at the Basic Telemetry section in the Session Explorer. The amount of used heap memory is now less than 3 MB.
PAGE 7
Memory Optimization
1. Create a profiling launch configuration. Choose BCI profiling without filters. Turn on allocation tracking and object lifetime profiling. Launch application in profile mode. 2. Watch the Memory Telemetry view.
The amount of used heap memory is more than 8 MB, which is too much for this application. 3. Take a memory snapshot. 4. Take a CPU snapshot. 5. Stop the profiling session.
COPYRIGHT 2007 INSTANTIATIONS, INC. ALL RIGHTS RESERVED.
PAGE 8
6. Open the memory snapshot. 7. Open the Class List view and sort classes by Shallow Size to find classes with the biggest amount of memory allocated to store objects of these classes.
The class with the biggest shallow size is java.util.HashMap. It is also the class with the biggest number of instances and one of the largest retained sizes. The number of instances of the class java.util.HashMap is near 50,000. The number of objects of the class java.util.HashMap$Entry is near 2,500. Because there are fewer entries than there are hash maps, it tells us that most of the hash maps must be empty (at least 47,500 of them). 8. Use java.util.HashMap as a name filter. 9. Look at the Object Lifetime view.
The Allocation hot spot method created by the biggest number of objects of java.util.HashMap class is the method com.instantiations.sample.memory.Thing.<init>. 50,000 objects of java.util.HashMap class have been created in the constructor of class Thing. 10. Open the CPU snapshot.
PAGE 9
11. Look at the Allocation Method List view sorted by Own Shallow size.
Methods with the biggest amount of shallow size are java.util.HashMap.<init>, com.instantiations.sample.memory.Thing.<init>, com.instantiations.sample.memory.ThingsTest.main. 12. Look at the Allocation Hot Spots view sorted by Shallow size.
Methods with the biggest amount of shallow size are the same three methods. 13. Open the implementation of the method com.instantiations.sample.memory.Thing.<init>.
14. Look at the implementation of the class Thing. The field named properties is initialized to an instance of HashMap when the instance of Thing is created. We know from the problem description that we are only setting the value of a property on about 5% of the instances of
COPYRIGHT 2007 INSTANTIATIONS, INC. ALL RIGHTS RESERVED.
PAGE 10
Thing. This suggests that a possible solution would be to leave the field properties uninitialized until we first set a property, treating a value of null as being equivalent to any empty HashMap. The Allocation views confirm this. 15. Change the code to initialize the field property only if a property is set on the thing (see the comparison of files Thing.java in the projects com.instantiations.sample.memory and com.instantiations.sample.memory.solved). 16. Profile the changed application. 17. Look at the Memory Telemetry view.
The amount of used heap memory is now less than 3 MB. 18. Take a memory snapshot and open it. 19. Look at the Class List view. Use java.util.HashMap as name filter.
The number of objects of the class java.util.HashMap is close to 2,500, which is what we would have expected.
PAGE 11
Used heap memory constantly increases. It possibly means there's a memory leak. 3. Force a garbage collection.
PAGE 12
This action hasnt affected the memory usage increase so the problem isnt uncollected garbage. 4. Take a memory snapshot. 5. Take a second memory snapshot after some period of time. 6. Open the second memory snapshot. 7. Look at the Biggest Objects view.
The biggest object is an instance of the class java.util.HashMap. 8. Look at the Class List view. Use java.util.HashMap as a name filter.
The number of instances of this class is near 33,000. Thats too high because only 1,000 different names for things are possible and only 5% of them can have a property. So the number of objects should be near 1,000. 9. Open the first memory snapshot.
PAGE 13
10. Compare these snapshots. The retained size of the class java.util.HashMap in the first snapshot (7,283,840) is much less than the retained size in the second snapshot (11,642,080). This indicates that at least one of the hash maps is probably growing without bounds, which is a common symptom of a memory leak. The most likely candidate is the hash map mapping instances of Thing to their names. This map could only be growing without bounds if two instances of the class Thing that have the same name are not comparing as equal. 11. Checking the class Thing, the problem quickly becomes apparent: the method equals was not implemented, so they are defaulting to using object identity. 12. Add the method equals (and hashCode, of course) to the class Thing (see the comparison of files Thing.java in the projects com.instantiations.sample.memory.leaks and com.instantiations.sample.memory.leaks.solved). 13. Profile the changed application. 14. Take a memory snapshot. 15. Look at the Class List view. Use java.util.HashMap as a name filter.
The number of instances of the class java.util.HashMap is near 1,000, which is what we expected. 16. Check the Memory Telemetry view to verify that the amount of memory being consumed is holding steady.
PAGE 14
Used heap memory constantly increases. It possibly means there's a memory leak. 3. Force a garbage collection. This action hasnt affected the memory usage increase so the problem isnt uncollected garbage. 4. Take a memory snapshot and stop the profiler. 5. Open the Memory Leak Candidates view. 6. Start Memory Leak Candidates discovering.
PAGE 15
The first found candidates with the biggest retained size are instances of the class java.util.HashMap$Entry. 7. Stop Memory Leak Candidates discovering. 8. Find path from GC root to the object java.util.HashMap$Entry.
GC root for the object java.util.HashMap$Entry is java.util.HashMap. 9. Look at the Object Lifetime view. Use java.util.HashMap as a name filter.
The number of instances of this class is near 25,000. Thats too high because only 1,000 different names for things are possible and only 5% of them can have a property. So the number of objects should be near 1,000. Besides it the average GC count for this objects is 7.
PAGE 16
10. Look at the Summary view of this snapshot. Total GC count is 15. So the average GC count for objects of class java.util.HashMap is a half of total GC count. 11. Go back to the Object Lifetime view.
Look at the allocation hot spots for the class java.util.HashMap. The constructor of class Thing has created the most of instances of the class java.util.HashMap and the lifetime of these instances is rather long. The hash map mapping instances of Thing to their names could only be growing without bounds if two instances of the class Thing that have the same name are not compared as equal. 12. Checking the class Thing, the problem quickly becomes apparent: the method equals was not implemented, so they are defaulting to using object identity. 13. Add the method equals (and hashCode, of course) to the class Thing (see the comparison of files Thing.java in the projects com.instantiations.sample.memory.leaks and com.instantiations.sample.memory.leaks.solved). 14. Profile the changed application. 15. Take a Memory snapshot. 16. Open the snapshot and look at the Object Lifetime view. Use java.util.HashMap as a name filter.
The number of instances of the class java.util.HashMap is near 1,000, which is what we expected.
PAGE 17
17. Check the Memory Telemetry view to verify that the amount of memory being consumed is holding steady. 18. Stop the profiler.
PAGE 18
Deadlock Detection
Profiled Application
Profiled application: Smorgasbord Project: com.instantiations.sample.deadlocks Description: This application implements a system of work of a smorgasbord. The menu consists of only soup. A guest should use a ladle and a spoon to eat the soup. Two guests came to the smorgasbord. While the first guest tries to eat his soup, the second one looks around.
Detecting Deadlocks
1. Create a Profiler launch configuration with the thread profiling enabled and launch the application in profile mode. 2. Watch the console view. Notice that first guest hasnt said Lunch is over. That means that he hasnt eaten. Its possible that there is a deadlock in the application. 3. Open the Deadlocks view.
One deadlock has been found. Threads First Guest and Second Guest have blocked each other.
PAGE 19
The first class of with blocked event type is Smorgasbord$Ladle and the class with blocked event type is Smorgasbord$Spoon. The first guest has taken a ladle from the table and the second guest took his spoon. So the first guest cant finish his lunch. 5. Change the first synchronized block (ladle) for the first guest so that it closes before opening the second synchronized block (spoon). See the comparison of files Smorgasbord.java in the projects com.instantiations.sample.deadlocks and com.instantiations.sample.deadlocks.solved. 6. Profile the changed application. 7. Watch the console view. The first guest has finished his lunch because the second guest couldnt take his spoon.
PAGE 20
Prerequisites
1. Eclipse WTP to be installed. 2. Any supported J2EE server. 3. Start Eclipse. For this demo we use WTP version 2.0 and Apache Tomcat v5.5 server.
PAGE 21
PAGE 22
12. Profile the application using Profile With CodePro As item in the context menu.
PAGE 23
Profiling perspective opens after profiling has been started. 13. Take CPU snapshot after request served. 14. Open Method List view.
There are com.instantiations.sample.j2ee.DemoServlet methods in the list. Thats mean that J2EE application has been profiled.
PAGE 24
15. Lets consider another way to profile J2EE application. Start profiling of Apache Tomcat server.
PAGE 25
17. Run target J2EE application via browser (use link http://localhost:8080/com.instantiations.sample.j2ee/DemoServlet).
18. Go to Eclipse window. Target application has been profiled on server. 19. Lets consider managing of profile mode launch configuration. Use Open Profile Dialog item in the profiling menu.
PAGE 26
PAGE 27