Oracle8i Java Developer's Guide Release 3 (8.1.7) Part Number A83728-01 |
Library | Service | Contents | Index

## Memory Profiling Utility

The purpose of the Memory Profiling Utility (MemStat) is to trace, profile, and report on the allocated memory that is accessible through static variables in your Oracle8i Java program. You can then use the information in this report to locate and eliminate unnecessary static data in your Java classes, thereby reducing the static footprint of your Java program and improving the performance of repeated Java calls into the database.

The Oracle8i JVM uses three kinds of memory:

- call memory, which exists for the duration of a (possibly recursive) call into the database

- session memory, which exists for the duration of the session connected to the database

- permanent or global memory, which persists as long as the database instance is running

Java language semantics specify that static variables persist across calls. At the end of each call, the Oracle8i JVM copies the call memory that is accessible through the static variables in each class into session memory so that it can be saved and restored on subsequent calls to methods in those Java classes. If there is a lot of static data or a complex graph of interconnected objects, then there is considerable overhead during the end-of-call processing while the JVM allocates session memory and copies the static data to it.

A typical technique for tuning object-oriented programs for faster performance is to eliminate the allocation of unnecessary objects from your program. For example, you can create a static instance of a commonly used object and reuse it rather than creating a new one every time you need it. However, the interactions among the different database memories complicate such techniques, and can require analysis of the speed trade-off for allocating dynamic objects versus the space trade-off for the end-of-call copying of static objects. If a static object is large, or if there are many such objects, or if there are many calls, then the speed advantage gained by caching the object may be lost, due to the traversal of the object graph during end-of-call processing.

### How MemStat Works

Depending on how you invoke it, MemStat will analyze either a single class or all classes that are loaded into the current session. For each class, MemStat enumerates the static variables of the class. These variables are known as the roots. Depending on the structure of each variable, MemStat performs three different analyses:

- If the variable is a primitive object, such as an integer, MemStat records its class and size.

- If it is a non-primitive object (for example, one that refers to another object), MemStat follows the reference and recursively enumerates all objects to which it refers.

- If it is an array, MemStat enumerates all elements of the array.

This process is repeated recursively until all objects reachable from all static variables have been recorded. Because it is possible for large object graphs to contain cycles, MemStat also records any circular references it encounters during the analysis.

### Using MemStat

The purpose of MemStat is to analyze and report on the object graph accessible from the static variables in your program. You can invoke the analysis directly from any point in your program, and you can also register it to run at the end of a call.

Because there is no standard output mechanism for database calls, MemStat produces its report in the form of HTML files, in a directory you specify. When the report is finished, you can view these files with any HTML-capable Web browser.

MemStat is implemented in three static methods on the class `oracle.aurora.memstat.MemStat`.

You can call it in three different ways:

- to report immediately on the static variables in a single class

- to report immediately on the static variables of all classes used in the current session

- to report at end-of-call on the static variables of all classes used in the current session

The method call for reporting on a single class is:

    MemStat.writeDump (Class MyClass, String outputPath, String filePrefix);

The method call for reporting on all loaded classes is:

    MemStat.writeDump (String outputPath, String filePrefix);

The method call for reporting on all loaded classes at the end-of-call is:

    MemStat.writeDumpAtEOC (String outputPath, String filePrefix);

The outputPath parameter represents the directory in which the MemStat reports are generated. The outputPath string must be in a file name format that is suitable to the platform on which the report is generated. For example, `/home/base/memstat` is suitable for a Solaris platform; the Windows format might be `c:\\base\\memstat`. Note that Java requires doubling of the backslashes inside a string, but not the forward slashes.

The `filePrefix` is the base file name for the HTML files that are generated in the outputPath directory. Because MemStat reports can be voluminous, and many Web browsers have limitations on the size of the files they can browse, MemStat breaks long reports into separate files. The `filePrefix` is the basis for all file names in a given report and is augmented by an incremental numeric suffix. If, for example, the test report produces three files, the main report file will be named `test.htm`, and additional report files will be named `test1.htm` and `test2.htm.`

If you call MemStat more than once in a given call, be careful to use different base names or different output directories, lest the subsequent reports overwrite the previous ones. For example, if you call MemStat before and after you perform some memory-consuming operation, naming the first report before and the second report after will prevent name collisions, while still writing the report files into the same directory. Using multiple directories is more complicated: you must remember to grant separate FilePermissions (see below) for each directory in which you want to write.

Here are some sample MemStat calls:

    MemStat.writeDump (MyClass.class, "c:\\base\\memstat", "myclass");
    MemStat.writeDump ("/home/base/memstat", "test");
    MemStat.writeDumpAtEOC ("/home/base/memstat", "eoc");

### MemStat Permissions

MemStat requires certain permissions to be granted to the user or role under which it runs. Because MemStat runs in the Oracle server process, these permissions grant access to the resources that MemStat requires:

- Access to the private variables of the objects in the graph. If this permission is not granted, MemStat will still run, but it will not trace any objects pointed to by private variables.

- Access to the Java run-time system for determining which classes are loaded in the current session. If this permission is not granted, MemStat will find zero classes loaded and will generate an empty report.

- Access to the server file system where the MemStat HTML reports are generated. If this permission is not granted, MemStat will raise an exception when it tries to create the report files.

The following SQL statements grant these permissions to user JIM:

    call dbms_java.grant_permission ('JIM',

    	'SYS:java.lang.reflect.ReflectPermission', 'suppressAccessChecks', null);

    call dbms_java.grant_permission ('JIM',
    	'SYS:oracle.aurora.security.JServerPermission', 'JRIExtensions', null);

    call dbms_java.grant_permission ('JIM', 'SYS:java.io.FilePermission',
    	'/home/base/memstat', 'read,write');									// Solaris

    call dbms_java.grant_permission ('JIM', 'SYS:java.io.FilePermission',
    	'c:\base\memstat', 'read,write');								// Windows

If the Oracle Server is running on a Windows platform, the output file path named in the MemStat call is subtly different from the path in the SQL grant_permission call. In Java strings, you must use double backslashes; in SQL you need only one backslash.

### The MemStat Report Format

This section describes the format of the MemStat report; see the example below. You can browse the MemStat output report with any HTML-capable Web browser. To do this, point the browser at the base file name that is specified, for example, `c:\base\memstat\test.htm`.

The report begins with a summary of the memory usage at the time MemStat is invoked. This summary should give you an overall idea of the amount of memory used by the Java call that you are analyzing.

Following the summary is a list of the unique classes that are traversed during the MemStat analysis. For every object found during the memory analysis, MemStat has recorded its class and its size in each of call, session, and permanent memory. The largest objects are sorted first, because eliminating these will yield the largest performance improvement. The list is actually sorted by the largest of these three sizes, calculated as max (call, max (session, permanent)). For each class, this table also shows how many bytes are occupied by objects of that class, how many objects there are, their minimum, maximum and average size, and for arrays, the standard deviation of the sizes.

Following the class summary is one or more tables describing each root object. The title of the object describes the package and class of the object. Each row of the table describes:

- a field of the object

- a description of the object in that field

- the total size of the object in each of the three memory spaces

Following the root objects are the objects pointed to by the roots; the objects are separated by a dividing rule. One, two, or three tables describe each object:

- the object itself

- any other objects that the object refers to

- any objects that refer to this object

The title for each object describes the memory in which the object resides: Call, Session, or Permanent. Each object is described by:

- a unique identifier

- the output of applying the `toString()` method to the object

- the object's direct size: the size of the object header and the fields of the object

- the object's total size: the sum of the sizes of all the objects to which it refers

An object that refers to another object is linked by an HTML link to the tables representing the object to which it refers. You can navigate the object graph using these links as you would navigate hyperlinks in a text document.

### Sample Output

MemStat Results

2000-06-01 17:07:05.645

Run-Time Values
Session Size | 143360
NewSpace Size | 262144
NewSpace Enabled | true
Intern Table Size | 261814

Total Memory Allocation
| Call | Session | Permanent
Objects | 726 | 926 | 3217
Total Size | 54861 | 39348 | 127418
Minimum | 12 | 12 | 12
Maximum | 16396 | 2060 | 8076
Average | 75.6 | 42.5 | 39.6
Std Deviation | 679.2 | 93.7 | 233.7

Allocated Objects by Class (Call, Session, Permanent)
Class | Bytes | Objects | Minimum | Maximum | Average | Standard Deviation
char[] | 25316 | 5134 | 43296 | 161 | 104 | 1177 | 2 | 0 | 0 | 16384 | 800 | 8064 | 157.2 | 49.4 | 36.8 | 1,283.2 | 105.0 | 276.9
java.lang.String | 3816 | 3240 | 30528 | 159 | 135 | 1272 |  |  |  |  |  |  |  |  |  |  |  |
java.util.Hash table$Entry | 4956 | 10696 | 12460 | 177 | 382 | 445 |  |  |  |  |  |  |  |  |  |  |  |
byte[] | 8195 | 2421 | 2107 | 2 | 34 | 57 | 3 | 0 | 0 | 8192 | 2048 | 1024 | 4,097.5 | 71.2 | 37.0 | 4,094.5 | 344.2 | 143.3

Objects Accessible From java.util.Properties
Field | Reference | Total Size
`keyValueSeparators` | `946: java.lang.String` | 0 | 0 | 50
`strictKeyValueSeparators` | `948: java.lang.String` | 0 | 0 | 40
`specialSaveChars` | `950: java.lang.String` | 0 | 0 | 54
`whiteSpaceChars` | `952: java.lang.String` | 0 | 0 | 46
`hexDigit` | `954: char[16]` | 0 | 0 | 44

| Copyright © 1996-2000, Oracle Corporation. All Rights Reserved. |
Library | Service | Contents | Index