diff --git a/dev-doc/API_policy.md b/dev-doc/API_policy.md new file mode 100644 index 00000000..9edcff16 --- /dev/null +++ b/dev-doc/API_policy.md @@ -0,0 +1,38 @@ +# Memory Analyzer API Policy + +This document provides the current API Policy for Memory Analyzer. + +## Purpose + +Eclipse MAT is built on top of the Eclipse IDE framework, and the components can +be embedded inside other deployments. As an OSGI framework-capable runtime, +the components export known consistent APIs that allow other developers and +components to work together within the IDE. + +For example, the [Eclipse MAT Calcite Plugin](https://github.com/vlsi/mat-calcite-plugin) +plugs directly into the Eclipse IDE and interacts with the Eclipse MAT +components to enhance its functionality. + +## Declared API + +The declared APIs in Memory Analyzer are provided as public and documented. The +API compatibility between different versions of Memory Analyzer should be +reflected by the version numbers, following the [Eclipse versioning policy](https://github.com/eclipse-platform/eclipse.platform/blob/master/docs/VersionNumbering.md). + +## Some examples + +- Changes to the API - adding new APIs or deprecating APIs should be documented +and communicated to the community (e.g. via GH issue and/or mailing list). + +- Deprecated API should be available for at lease one major release. + +## Provisional and internal API + +Provisional APIs should be used while development is occurring. If successfully +adopted, they might become declared APIs. If not, they can be removed. In any +situation, the community should be notified. + +## Tooling + +See the [Contributor Reference](Contributor_Reference.md) for some notes on API +tooling and configuration. diff --git a/dev-doc/Extending_Memory_Analyzer.md b/dev-doc/Extending_Memory_Analyzer.md new file mode 100644 index 00000000..4d774441 --- /dev/null +++ b/dev-doc/Extending_Memory_Analyzer.md @@ -0,0 +1,558 @@ +# Extending Memory Analyzer + +## Introduction + +The Memory Analyzer tool offers several possibilities to extend it. This page +contains an overview of the different extension points and what can be achieved +with them. + +Within the extensions one will usually extract certain pieces of information +from the objects in the heap dump. See [Reading data from heap dumps](Reading_data_from_heap_dumps.md) +for more details on how to read data from a heap dump. + +## Setting up a development environment for writing extensions + +It is not necessary to download the source of Memory Analyzer to be able to +write extensions. A recent binary version is sufficient. + +### Development environment + +1. Have a copy of an Eclipse Java Development environment installed +2. Download and install latest copy of Memory Analyzer + +### Target platform setup + +Create MAT as a target platform: +1. Windows->Preferences->Plug-in Development->Target Platform +2. Add->Nothing->Next +3. Name: MAT +4. Locations->Add->Installation +5. Location: path_to_MAT/mat +6. Finish +7. Select MAT as active target platform + +## Creating a plug-in project + +1. File->New->Other->Plug-in project +2. Name: MAT Extension +3. ->Next +4. Execution Environment: (pick current Java generation) +5. No activator (unless you are doing something complicated) +6. No UI contribution +7. No API analysis +8. No template +9. ->Finish + +### Configure depedencies + +1. add `org.eclipse.mat.api` (to allow use of the API) +2. Save (cntl-S) + +### Configure extensions + +1. select `org.eclipse.mat.api.nameResolver` (to integrate with extensions) +2. ->Finish +3. click on impl +4. Adjust package name and class name to suit +5. ->Finish +6. Add before the class definition an annotation, + + ```java + @Subject("java.lang.Runtime") + ``` + +7. Organize imports (cntl-shift-O) +8. Edit the code to perform the required function. For example + + ```java + public String resolve(IObject object) { + // return null; + return "The Java runtime of size " + object.getUsedHeapSize(); + } + ``` + +9. Save + +Tip - If using Eclipse, note the javadoc help for `IObject`, +`IClassSpecificNameResolver`. Note the method list for object. + +### To test + +Select Plug-in, Run As->Eclipse Application. + +### To package + +1. File->Export->Plug-in Development->Deployable plug-ins and fragments +2. ->next +3. select plug-in +4. Destination: Directory: path_to_MAT/mat +5. ->Finish + +## The Name Resolver Extension + +The name resolver extension point provides a mechanism to give a readable +description of an object, similar to what a `toString()` method will do. Some +extensions which MAT provides are to show the content of objects representing +String, to show the bundle symbolic name for Equinox classloaders, to show the +thread name for Thread objects, etc. You can create and contribute your own +resolvers. + +The extension should implement the `IClassSpecificNameResolver` interface which +defines a single method. + +```java +public String resolve(IObject object) throws SnapshotException; +``` + +The method takes an `IObject` as an argument and should return a string +representation. + +To specify the class for which the resolver should be used one can use the +annotation `@Subject`. + +```java +@Subject("x.y.z.MyClass") +public class MyClassResolver implements IClassSpecificNameResolver { + public String resolve(IObject obj) throws SnapshotException { + // implementation + } +} +``` + +The method `getClassSpecificName()` of `IObject` will look for extensions which +match the class of the object and execute the `resolve()` method to return the +resolved String. Thus it is relatively easy to return a description based on one +or more String fields, as strings are already resolved. + +Here is a sample implementation that will return the name of an Eclipse Job: + +```java +@Subject("org.eclipse.core.runtime.jobs.Job") +public class JobNameResolver implements IClassSpecificNameResolver +{ + @Override + public String resolve(IObject object) throws SnapshotException + { + IObject name = (IObject) object.resolveValue("name"); + if (name != null) return name.getClassSpecificName(); + return null; + } +} +``` + +## Queries in Memory Analyzer + +### Introduction to Queries + +Most of the functionality in Memory Analyzer which is exposed to the user of the +tool is provided via queries implementing the `IQuery` interface, for example +"Histogram", "Retained Set", etc. + +Queries extract and process data from the heap dump using the MAT API, and +provide the result to the user in the form of a table, a tree, free text, etc. +Queries show up in the "Queries" menu of the tool, and often in the context +menus on objects. + +An important feature of the queries is that they can "collaborate", i.e. the +user can use (part of) the result of one query and pass it as input parameters +to another query. + +An example of such "cooperation" - you select "Histogram" to show a class +histogram of all objects, then choose say `java.util.HashMap`. From the context +menu call "Retained Set". The retained set is using as input the results of the +histogram selection. You can then select a line in this retained set and pass +the corresponding objects to yet another query. + +### The `IQuery` Interface + +To implement a query one needs to implement the `IQuery` interface. The +implementation should provide a (default) constructor without parameters. + +The IQuery interface defines just one method: + +```java +public IResult execute(IProgressListener listener) throws Exception; +``` + +As a parameter one gets only a progress listener `IProgressListener` to report +progress. All other input that a query needs is deaclared with annotations on +the fields of the query and injected from Memory Analyzer at runtime. The +fields used for arguments injection should be declared public. + +For more details on getting input, see the Passing Arguments section (below). + +The return type of the execute method is `IResult`, which is a marker interface. +The different result types are described in the section Query Results (below). + +### Query Scope + +Queries are stateless. Every time the user executes a query a new instance of +the `IQuery` implementation is created. The required input is injected into the +fields of the instance and the execute method is called. + +### Describing the Query with Annotations + +When you write a query it will appear in the context menus, and Memory Analyzer +will open an Arguments Wizard for specifying the required arguments. The wizard +will also show some help for the query and its arguments. + +The metadata - how a query will be named, under which category (sub-menu) it +will appear, the help text, etc are all provided by annotating the query. + +The following meta-data related annotations are available and should be at the +`Class` level for the query. + +| Annotation | Description | +|------------|-------------| +| @CommandName | used for command line and query browser | +| @Name | the visible name on the menu, `nn\|` to set order | +| @Category | the menu section (sub-menu), `/` to cascade, `nn\|` to set order | +| @Help | explanation of query | +| @HelpUrl | link into the help system | +| @Icon | icon for the query (shown in the menu) | +| @Usage | example usage – defaults to command name + args | + +The values can also be externalized. To do so, put them into an +`annotations.properties` file in the package directory. + +#### Example annotations + +```java +@Category("Sample Queries") +@Name("List Jobs Query") +@Help("This is a sample query, which lists all jobs with a given name") +public class SampleQuery implements IQuery { + ... +} +``` + +To externalize these values, `annotations.properties` will look something like: + +```properties +SampleQuery.category = Sample Queries +SampleQuery.name = List Jobs Query +SampleQuery.help = This is a sample query, which lists all jobs with a given name +``` + +### Passing Arguments to a Query + +A nice property of queries is that they can interact with each other. In other +words, parts of the result from one query (say one line in a histogram) can be +passed to a different query using the context menus. + +To support this queries need to declare what kind of arguments they require and +delegate to the Memory Analyzer to collect this information. Memory Analyzer +will inject it into the queries before executing them. If needed, Memory +Analyzer does this by opening the Arguments Wizard. + +To declare an input parameter a query has to define a public field and annotate +it with the `@Argument` annotation. To provide a help message specific on the +concrete argument, add also the `@Help` annotation to the public field. + +The following types are currently supported as arguments: + +| Argument type | Description | +|---------------|-------------| +| `ISnapshot` | the snapshot corresponding to the currently open editor | +| `IHeapObjectArgument` | good way of getting objects | +| `String`, `Pattern`, `int`, `boolean`, `float`, `double` | supplied directly via wizard or command line | +| `IContextObject` | row with one object | +| `IContextObjectSet` | row with multiple objects or OQL query to return those objects | +| `IQueryContext` | a more general way of extracting information about the snapshot which is not tied to the snapshot API | +| arrays or lists of the above | for multiple items | +| enums | can be used to provide a fixed choice list | +| `File` | for input or output files | + +### Comparison Queries + +Comparison queries are run from the Compare Basket but are invoked in a similar +way. Each row of the Compare Basket is a whole result of a previous query; +either a tree or table. + +Queries with arguments suitable for a comparison operation are only offered in +the Compare Menu and not from the editor pane. Comparison arguments are as +follows, all arguments should be a `List` or `[]` array of: + +| Compare Argument | Description | +|------------------|-------------| +| `IResultTable` | for comparison queries only operating on tables | +| `IResultTree` | for comparison queries only operating on trees | +| `IStructuredResult` | for comparison queries operating on tables and trees | +| `RefinedTable` | for comparison queries only operating on tables, uses the filtered and sorted version of the previous result with any derived columns like retained size | +| `RefinedTree` | for comparison queries only operating on tables, uses the filtered and sorted version of the previous result with any derived columns like retained size | +| `RefinedStructuredResult` | for comparison queries operating on tables and trees, uses the filtered and sorted version of the previous result with any derived columns like retained size | +| `ISnapshot` | the snapshots corresponding to the tables / trees, in the same order | + +Consider using `RefinedStructuredResult` for your comparison queries as the query may then be more flexible for the end user. + +Some standard arguments are also available to comparison queries: + +| Argument type | Description | +|---------------|-------------| +| `String`, `Pattern`, `int`, `boolean`, `float`, `double` | supplied directly via wizard or command line | +| enums | can be used to provide a fixed choice list | +| `File` | for input or output files | + +### Qualifications on Query Arguments + +Parameters on the `@Argument` annotation can be used to specify some further +restrictions and hints to be followed by the wizard and during injection. + +```java +@Argument +public ISnapshot snapshot; + +@Argument(advice = Advice.HEAP_OBJECT, isMandatory = false, flag = Argument.UNFLAGGED) +public int[] objects; + +@Argument(isMandatory = false, flag = "t") +public int thresholdPercent = 1; +``` + +| Annotation parameter | Description | +|----------------------|-------------| +| isMandatory | a boolean parameter to tell MAT if it can execute the query without the argument | +| flag | a String used instead of the field name to identify the argument in the command line and in the query browser | +| Advice | qualifies the way data is inserted into the field (see below) | + +Advice arguments can be found in `org.eclipse.mat.query.annotations.Argument` as +the `Advice` enum. + +| Advice argument | Description | +|-----------------|-------------| +| Advice.HEAP_OBJECT | the int or Integer is an object id, not a number | +| Advice.SECONDARY_SNAPSHOT | the snapshot is another snapshot, which should be prompted for, not the current one | +| Advice.CLASS_NAME_PATTERN | the pattern will be used to match class names | +| Advice.DIRECTORY | the file parameter is meant to be a directory | +| Advice.SAVE | the file parameter is meant to be used to save data | + +#### Reading data from supplied arguments + +See [Reading data from heap dumps](Reading_data_from_heap_dumps.md) for how to +extract data from supplied arguments, including use of `ISnapshot`, `IObject` +and the use of object IDs. + +### Calling One Query from Another + +Supplied queries are not a Memory Analyzer API, so user written queries should +not link to them directly. It is possible to call them by name, though the query +names and arguments can vary from release to release. + +```java +String query = "SELECT s, toString(s) from java.lang.String s"; +IResult ir = SnapshotQuery.lookup("oql", snapshot).setArgument("queryString", query).execute(listener); +``` + +An enum argument may need to be set using a parsed string, as calling via +`setArgument` often doesn't work as the enum type is inaccessible. + +```java +SnapshotQuery query = SnapshotQuery.parse("dominator_tree -groupby BY_CLASSLOADER", snapshot); +IResultTree t = (IResultTree)query.execute(new VoidProgressListener()); +``` + +### Query Results + +- `TextResult` - A simple result that renders its input as text. +- `IStructuredResult` - A way of display data about lots of objects + - `IResultTable` - A table of objects + - `Histogram` - A table of objects where each row is all the objects of + one class + - `ListResult` - A way of displaying a Java List of things, where the + fields from each thing are also given + - `PropertyResult` - A way of displaying details about one object based + on a list of attributes + - `IResultTree` - A tree of objects +- `IResultPie` - A pie chart +- `QuerySpec` - A good way of displaying the results of executing another query + +## Reports in Memory Analyzer + +Several queries can be combined into a report which could then be run from the +Run Report... menu option or in batch mode. + +### Report definition + +The report definition is written in XML and can be validated using the schema +held in `org.eclipse.mat.report/schema/report.xsd`. The result of running a +report will be an HTML page or a CSV data file. Queries can be run using the +`query` element, using the command `element` to specify which command should be +run. + +Other reports can be run using the `template` element. The `section` element can +be used to combine multiple `query`, `template` and `section` elements and is +displayed in a report as a collapsible part or a separate file. + +Two examples show how the report definition is written. `overview.xml` has a +section and `suspects.xml` also has a `template` element referencing another +report to be run and included. They are available in `plugins/org.eclipse.mat.api/META-INF/reports/`. + +The `param` element allows output to be controlled: + +- The params can be used to control generation of tables - as HTML or CSV files, +to limit or increase the number of lines displayed, and to omit, sort or filter +columns. +- Some params just control the current section - some also control any inner +sections unless overridden. +- A param can also be used elsewhere in the report as `${param_name}` - in the +command name and other param values. +- Values are documented in `org.eclipse.mat.report.Params` interface as well as +in the `Params.Html` and `Params.Rendering` javadoc. +- Parameters can be passed to a report definition using `ParseHeapDump` +- A param value given on the command line will override a value given in a +report definition. + +```bash +ParseHeapDump myheapdump.hprof -myparam=myparam_value myreport.xml +``` + +The report definition can be tested as Run Expert System Test > Run Report. + +### Report definition extension point + +If a report definition is incorporated into a plug-in then the report definition +extension point should be used. Then when the new plug-in is installed into MAT +the report will be available to run from the Memory Analyzer GUI. + +Values in the report definition can then be externalized using a definition in +the `plugin.properties` file and referred to by `%myval Default value`. + +### Executing a Report in Unattended Mode + +Once you create a Report extension you can find it next to other reports like +the "Leak Suspects" in the Memory Analyzer GUI. Besides this, one can execute +reports in an unattended mode by running the "org.eclipse.mat.api.parse" +application. + +Here is an example how to setup a Run Configuration to execute the report +"my_repory" located in the plugin "my_report_plugin": + +- Run As -> Run Configurations +- Set "Run An Application" to "org.eclipse.mat.api.parse" +- Set the Program arguments to +```bash +${file_prompt} my_report_plugin:my_report +``` + +When you run this you will get a popup to select a heap dump file. It will be +then parsed and the report will be executed for it. The result however is not +open in the IDE, it is saved in the file system next to the dump. + +#### Parameters + +You can also define options on the command line. This can be as + +```bash +${file_prompt} "-my_parm=my special value" my_report_plugin:my_report +``` +and then access the variable inside the report XML as + +```xml +
+ + + my_query -myopt "${my_parm}" + +
+``` + +## Request Resolvers + +A request resolver is a piece of coding which is capable of extracting details +about what a thread was doing, using the information from the thread object and +its java local objects. The information provided by a request resolver is +included in the Leak Suspects report. + +When is this useful? There are often OutOfMemoryErrors which are not caused by a +memory leak, but rather by some "greedy" operation - an attempt to load a huge +file fully into memory, an attempt to build scan a whole DB table and keep the +results in memory, etc... In such cases the Leak Suspect report will often point +to the thread as the suspect object, because its local objects (objects on the +thread's stack) are eating too much memory. In such cases it is very helpful to +know what the thread was doing and to get some insights on this activity. + +Examples: + +- tell that a thread was processing an HTTP request and extract the concrete request and some parameters +- show an SQL statement that has been processed when an OOM error occured +- display the name of the Eclipse Job which has been processed +- etc... + +### The `IRequestDetailsResolver` Interface + +To implement a request resolver one needs to implement the +`IRequestDetailsResolver` interface. To specify for which type of local objects +this request resolver can provide information, use the the `@Subject` annotation +on the implementation class. + +The interface defines just one method: + +```java +void complement(ISnapshot snapshot, IThreadInfo thread, int[] javaLocals, int thisJavaLocal, + IProgressListener listener) throws SnapshotException; +``` + +The complement method will be called by Memory Analyzer whenever it collects +information for a thread and the thread has a local object (somewhere on the +stack) which matches the type specified by `@Subject`. As parameters one will +receive all necessary context information to extract the needed information: + +| parameters | description | +|------------|-------------| +| snapshot | the whole dump | +| thread | a IThreadInfo object representing the thread being analyzed | +| javaLocals | all the local variables, as object IDs | +| thisJavaLocal | the object ID of the local object matching the `@Subject` | + +Within the `complement()` method one should extract helpful information about +the activity of the thread and add it to the `IThreadInfo` object using the +`addRequest()` method. The `addRequest()` method takes two parameters - a +String with short description appearing on the first page of the Leak Suspects +report, and an IResult with more details about the request (could be a table +with all properties, etc...). + +Here is a code sample for a request resolver: + +```java +/* Specify that I can extract information from ProgressManager$JobMonitor objects */ +@Subject("org.eclipse.ui.internal.progress.ProgressManager$JobMonitor") +public class JobRequestResolver implements IRequestDetailsResolver { + + @Override + public void complement(ISnapshot snapshot, IThreadInfo thread, + int[] javaLocals, int thisJavaLocal, IProgressListener listener) + throws SnapshotException { + IObject monitor = snapshot.getObject(thisJavaLocal); // get the IOjbect for the JobMonitor + IObject job = (IObject) monitor.resolveValue("job"); // get the value of the job field + String jobName = job.getClassSpecificName(); // get the symbolic represenation of the job + + String summary = "This thread executes the job [" + jobName + "]"; + IResult sampleDetails = new TextResult("Job object is = [" + job.getDisplayName() + "]"); + + thread.addRequest(summary, sampleDetails); // add the request information + thread.addKeyword(jobName); // add the job name to the keywords + } +} +``` + +This sample request resolver will add to the leak suspect report a line like: + +``` +This thread executes the job [Sample greedy job] +``` + +if the thread was processing an Eclipse job. It will add as details the object +instance of the Job implementation. + +## Adding a New Heap Dump Format + +Memory Analyzer can also be extended to support more heap dump formats. A +detailed description how to do this can be found in the page +[Adding a new heapdump format](Adding_a_new_heapdump_format.md). + +## Contributing back to the project + +If your extension to Memory Analyzer would be useful to other people, please +consider contributing it back to the project. diff --git a/dev-doc/Index_files.md b/dev-doc/Index_files.md new file mode 100644 index 00000000..1901823d --- /dev/null +++ b/dev-doc/Index_files.md @@ -0,0 +1,63 @@ +# Index files + +Memory Analyzer uses several indexes to enable access to different parts of the +snapshot. + +| Index name | description | +|------------|-------------| +| IDENTIFIER | IntToLong object ID to object address | +| O2CLASS | object ID to class ID | +| A2SIZE | array object ID (or other non-fixed size object) to encoded size (32-bits) | +| INBOUND | object ID to list of object IDs | +| OUTBOUND | object ID to list of object IDs | +| DOMINATED | Dominated: object id to N dominated object ids | +| O2RETAINED | object ID to long | +| DOMINATOR | Dominator of: object id to the id of its dominator | +| I2RETAINED | cache of size of class, classloader (read/write) | + +## IntIndexReader + +For an index file like O2CLASS, the file is stored as many `ArrayIntCompressed` +followed by an index: `IntIndexReader`. There is a special adjustment to cope +with >2^31 entries files as that can be needed for 1 to N files. + +On reading there is a `SoftReference` cache of those `ArrayIntCompressed` pages. + +The data is read using a `SimpleBufferedRandomAccessInputStream` which just has +local buffer. + +## LongIndexReader + +LongIndexReader is similar (without the adjustment for 2^31 entries). + +## PositionIndexReader + +PositionIndexReader is similar (without the adjustment for 2^31 entries). + +## 1 to N reader + +`IntIndex1NReader` has two parts: a body and an header, and a final `long` of +the position of the split in the file. + +For an input, use the header to find the position of the start in the body and +the header via (index+1) to find the position of the next entry. +Read data between the two from the body. + +## Random Access File caching + +HPROF random access to GZIP compressed files to read fields and array contents + +- `org.eclipse.mat.hprof.DefaultPositionInputStream` + - `org.eclipse.mat.parser.io.BufferedRandomAccessInputStream` + - `HashMapLongObject` + - `[*N] page` + - `[*N] SoftReference` + - `buffer byte[512]` + - `org.eclipse.mat.hprof.CompressedRandomAccessFile` + - `org.eclipse.mat.hprof.SeekableStream` + - `[*N} org.eclipse.mat.hprof.SeekableStream$PosStream` + - `SoftReference` + - `org.eclipse.mat.hprof.GZIPInputStream2` + - `io.nayuki.deflate.InflaterInputStream` + - `inputBuffer byte[16384]` + - `dictionary byte[32768]` diff --git a/dev-doc/MAT_capabilities.md b/dev-doc/MAT_capabilities.md new file mode 100644 index 00000000..3416e194 --- /dev/null +++ b/dev-doc/MAT_capabilities.md @@ -0,0 +1,38 @@ +NOTE this page is here for archival purposes only. + +# MAT Capabilities + +This document provides some sample [capability definitions](https://wiki.eclipse.org/Eclipse/Capabilities) +for the Memory Analyzer (MAT). It describes: + +1. Where to find the existing Capabilities plug-in in SVN +2. Or how to implement your own Capabilities for Memory Analyzer + +## Existing Capabilities Plug-in + +The plug-in `org.eclipse.mat.ui.capabilities` contains Capabilities definition +for Memory Analyzer. + +The plug-in can be found in the project repo at: + +`plugins/org.eclipse.mat.ui.capabilities` + +[Link](https://github.com/eclipse-mat/mat/tree/master/plugins/org.eclipse.mat.ui.capabilities) + +## Capabilities Implementation + +The code snippet below shows how to turn off Memory Analyzer functionality in +the workbench via Capabilities: + +```xml + + + + + +``` diff --git a/dev-doc/Reading_data_from_heap_dumps.md b/dev-doc/Reading_data_from_heap_dumps.md new file mode 100644 index 00000000..622c651f --- /dev/null +++ b/dev-doc/Reading_data_from_heap_dumps.md @@ -0,0 +1,246 @@ +# Reading data from heap dumps (programmatically) + +The Memory Analyzer offers an API which one can use to open a heap dump and +inspect its contents programmatically. This API is used by the MAT tool itself +to offer the different end-user features available in the tool. An overview of +this API is available on this page. + +## The ISnapshot interface + +The most important interface one can use to extract data from a heap dump is +`ISnapshot`. `ISnapshot` represents a heap dump and offers various methods for +reading object and classes from it, getting the size of objects, etc... + +To obtain an instance of `ISnapshot` one can use static methods on the +`SnapshotFactory` class. However, this is only needed if the API is used to +implement a tool independent of Memory Analyzer. + +If you are writing extensions to MAT, you typically will receive a reference to +an already opened heap dump either by injection or as a method parameter. See +[Extending Memory Analyzer](Extending_Memory_Analyzer.md). + +### Opening a snapshot using `SnapshotFactory` + +To open an existing heap dump in one of the supported formats call the +`SnapshotFactory.openSnapshot()` method. + +```java +public static ISnapshot openSnapshot(File file, IProgressListener listener) throws SnapshotException +``` + +As parameters pass the heap dump file and a valid progress listener (see below). + +When you are finished with using the `ISnapshot` instance call the +`SnapshotFactory.dispose(ISnapshot)` method to free the resources and unlock any +used files. + +### The `IProgressListener` interface + +The `IProgressListener` listener interface offers (as the name suggests) +functionality to report the progress of different computations. + +Usually if you are extending the tool then MAT will pass an instance of an +object implementing the interface to you. + +In case you are opening the heap dump on your own, you may need to create the +listener on your own. The tool provides some helper classes: + +| Listener class | Description | +|----------------|-------------| +| `ConsoleProgressListener` | Logs progress to Java stdout/console. | +| `VoidProgressListener` | Ignores progress. | +| `ProgressMonitorWrapper` | Can wrap the `org.eclipse.core.runtime.IProgressMonitor`. | +| `SimpleMonitor` | Can be used to generate several `IProgressListener` objects each handling a proportion of work from a supplied `IProgressListener`. | + +## The object model + +The following hierarchy of interfaces represents the object model that MAT +builds for objects in the heap. + +They can all be found in `org.eclipse.mat.snapshot.model.*` package. + +- `IObject` representing any object on the heap. + - `IClass` represents a `java.lang.Class`. + - `IInstance` represents an ordinary Java object instance. + - `IClassLoader` represents a classloader. + - `IArray` represents an array. + - `IObjectArray` represents an object array. + - `IPrimitiveArray` represents a primitive array. + +This model is pretty straightforward and easy to understand. However, there is +one major challenge – the memory needed to maintain such a model. As often there +are millions of objects in a heap dump, MAT is not keeping such a model through +the lifetime of an ISnapshot. Instead it gives every object an id (starting from +0 and growing by one) and uses these ids to obtain information about objects +(like its class, size, referenced objects, etc) from the `ISnapshot` instance. + +Also most of the heavy computations traversing potentially millions of objects +(e.g. calculating a retained size, computing paths, etc) are done without using +the object model described above. The use of the classes described here is +needed (and recommended) only when the full information about an object is +needed – including its field names and their (possibly primitive) values. + +## Single objects, objects id and address + +To get an object by its id use the method `getObject(int id)` of `ISnapshot`. + +Objects have also addresses (usually visualized as hexadecimal number next to +the object). One can map between object ids and addresses using the following +two methods of `ISnapshot`: + +```java + public long mapIdToAddress(int objectId) throws SnapshotException; + public int mapAddressToId(long objectAddress) throws SnapshotException; +``` + +If you already have an instance of `IObject` you can call `getObjectId()` and +`getObjectAddress()` directly. + +## Getting classes + +The `ISnapshot` interface offers the possibility to get a class by its fully +qualified name or get a collection of classes using a regex pattern. + +```java + public Collection getClassesByName(String name, boolean includeSubClasses) throws SnapshotException; + public Collection getClassesByName(Pattern namePattern, boolean includeSubClasses) throws SnapshotException; +``` + +Both methods return a collection of classes, as classes with the same name but +loaded with different class loaders are treated as separate classes. To get a +collection of all classes available in the heap dump, just call the +`getClasses()` method without any parameters + +## Get all instances of a class + +To get all instances of a certain class first obtain the class (or collection +of classes) and then call the `getObjectIds` method on the `IClass` instance: + +```java + public int[] getObjectIds() throws SnapshotException; +``` + +The returned `int[]` contains the ids of all objects of the class. + +## Inspecting referenced objects + +There are various possibilities to explore the outgoing references of an object. +The most performant way is to use the `getOutboundReferentIds(int)` methods of +`ISnapshot`. + +```java + public int[] getOutboundReferentIds(int objectId) throws SnapshotException; +``` + +This method takes an object id and returns an array containing all the ids of +all referenced objects. The reference objects include also object referenced by +artificially modeled references. This method gives a fast way to traverse the +object graph. + +The `IObject` interface also provides several ways to explore its references: + +```java + public List getOutboundReferences(); +``` + +A `NamedReference` allows you to look at the name of the reference, get the id +and the address of the referenced object, and also get the referenced object as +`IObject`. + +If you are looking for the value of a specific field or reference, then the most +convenient way to achieve it is to use the `resolveValue` method. + +```java + public Object resolveValue(String field) throws SnapshotException; +``` + +It takes as an argument a dot-separated path to the field of interest. This +means that one can access not only the fields of the object itself, but to +provide a path through some of the references. Here is an example: + +```java +IObject myObject = snapshot.getObject(objectId); +IObject fName = myObject.resolveValue(“department.customer.firstName”); +``` + +This code will go through the fields of myObject and will search for a field +named "department". If department itself is not a primitive MAT will find its +field "customer", and then find the field "firstName" in the object referenced +through "customer". + +If the field is of primitive type, then `resolveValue()` will return the +corresponding boxed class, allowing you to read these directly: + +```java +IObject hashMap = … ; // some IObject representing a HashMap +int size = hashMap.resolveValue(“size”); +``` + +## Printing objects + +The IObject interface defines several methods for getting a String +representation of the object. + +| Method | Description | +|--------|-------------| +| `getTechnicalName()` | returns a string in the format ` @
`. | +| `getClassSpecificName()` | returns a string in the format as described by a resolver (see below). | +| `getDisplayName()` | convenience method returning a combination of the technical name appended by the class specific name. | + +### Class Specific Name Resolvers + +Calling `getClassSpecificName()` on an object with a defined name resolver +allows for specific code to interpret the object (including referred) and +return a more readable string description. + +For example if you call it on an `IObject` representing a `java.lang.String`, +then it will return the value of the string. + +If you call it on an `IObject` representing a `java.lang.Thread`, it will return +the name of the Thread. This method however is not the toString() method of the +real objects that were put in the heap dump. The heap dump only contains the +objects and their values, but it is not possible to call methods of the +corresponding classes. The Memory Analyzer extracts information from the fields +of the objects and models the toString() behavior. + +It is possible to easily extend MAT by adding new ClassSpecificNameResolvers +using a defined extension point. The existing resolvers are available in +`org.eclipse.mat.inspections.*` package. You can register or contribute +additional resolvers to support a more pleasant experience. + +See the relevant section in [Extending Memory Analyzer](Extending_Memory_Analyzer.md) + +## Object sizes + +### Shallow size + +To get the shallow size of a single object, use the `getHeapSize` method of +`ISnapshot`: + +```java + public long getHeapSize(int objectId) throws SnapshotException; +``` + +If you have to compute the shallow size of a set of objects (e.g. the sum of the +shallow sizes of each instance of a certain class), then we recommend to use the +`getHeapSize(int[] objectIds)` method of ISnapshot and pass the ids of all +objects of interest as an array. This method uses some internal structures and +is executing the task in several threads (if more than one CPU is available), +therefore it will have better performance than looping over the objects and +calling `getHeapSize()` for each single object. + +### Retained Size + +To get the retained size of a single object, use the `getRetainedHeapSize()` +method of ISnapshot. + +```java + public long getRetainedHeapSize(int objectId) throws SnapshotException; +``` + +To get the retained size of a set of objects, first compute the retained set +using `int[] getRetainedSet(int[], IProgressListener)` and then call the +`getHeapSize(int[])` on the returned array with ids. + +The `getRetainedSet` method has two other “advanced” variants. Consult the API +reference inside the tool for more details.