Merge "[572596]: Add maximum retained heap of locals to stack frame row"
diff --git a/plugins/org.eclipse.mat.chart.ui/src/org/eclipse/mat/ui/internal/chart/ChartCanvas.java b/plugins/org.eclipse.mat.chart.ui/src/org/eclipse/mat/ui/internal/chart/ChartCanvas.java
index 6285e85..23f3361 100644
--- a/plugins/org.eclipse.mat.chart.ui/src/org/eclipse/mat/ui/internal/chart/ChartCanvas.java
+++ b/plugins/org.eclipse.mat.chart.ui/src/org/eclipse/mat/ui/internal/chart/ChartCanvas.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2010 SAP AG.
+ * Copyright (c) 2008, 2021 SAP AG and IBM Corporation.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -9,6 +9,7 @@
  *
  * Contributors:
  *    SAP AG - initial API and implementation
+ *    Andrew Johnson - disposal of resources
  *******************************************************************************/
 package org.eclipse.mat.ui.internal.chart;
 
@@ -177,6 +178,8 @@
     {
         if (cachedImage != null)
             cachedImage.dispose();
+        if (renderer != null)
+            renderer.dispose();
         super.dispose();
     }
 
diff --git a/plugins/org.eclipse.mat.chart.ui/src/org/eclipse/mat/ui/internal/chart/PieChartPane.java b/plugins/org.eclipse.mat.chart.ui/src/org/eclipse/mat/ui/internal/chart/PieChartPane.java
index 4825f14..89c84a8 100644
--- a/plugins/org.eclipse.mat.chart.ui/src/org/eclipse/mat/ui/internal/chart/PieChartPane.java
+++ b/plugins/org.eclipse.mat.chart.ui/src/org/eclipse/mat/ui/internal/chart/PieChartPane.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 2008, 2018 SAP AG, IBM Corporation and others.

+ * Copyright (c) 2008, 2021 SAP AG, IBM Corporation and others.

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

@@ -387,9 +387,13 @@
     @Override

     public void dispose()

     {

-        super.dispose();

         if (menu != null && !menu.isDisposed())

             menu.dispose();

+        if (label != null && !label.isDisposed())

+            label.dispose();

+        if (canvas != null && !canvas.isDisposed())

+            canvas.dispose();

+        super.dispose();

     }

 

 }

diff --git a/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/InitDTFJ.java b/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/InitDTFJ.java
index da4790a..27cb748 100644
--- a/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/InitDTFJ.java
+++ b/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/InitDTFJ.java
@@ -1,10 +1,10 @@
 /*******************************************************************************

- * Copyright (c) 2009,2018 IBM Corporation.

+ * Copyright (c) 2009,2021 IBM Corporation.

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -281,25 +281,21 @@
     {

         // Find a predefined DTFJ Adapter Plugin extension - use this to set

         // the provider for the new plugin

-        IExtension es = reg.getExtension("org.eclipse.ui.startup", "org.eclipse.mat.dtfj.dtfj"); //$NON-NLS-1$ //$NON-NLS-2$

-

-        // Second go at finding an extension for this bundle - the first

-        // might fail if there is no UI.

-        if (es == null)

+        IExtensionPoint extensionPoint = reg.getExtensionPoint("org.eclipse.mat.parser.parser"); //$NON-NLS-1$

+        if (extensionPoint != null)

         {

-            es = reg.getExtension("org.eclipse.core.contenttype.contentTypes", "com.ibm.dtfj.base"); //$NON-NLS-1$ //$NON-NLS-2$

+            for (IExtension es1 : extensionPoint.getExtensions())

+            {

+                if ("dynamic-dtfj".equals(es1.getSimpleIdentifier())) //$NON-NLS-1$

+                {

+                    return es1.getContributor();

+                }

+            }

         }

 

-        IContributor cont;

-        if (es != null)

-        {

-            cont = es.getContributor();

-        }

-        else

-        {

-            cont = ContributorFactoryOSGi.createContributor(getBundle());

-        }

+        IContributor cont = ContributorFactoryOSGi.createContributor(InitDTFJ.getDefault().getBundle());

         return cont;

+

     }

 

     /**

@@ -327,19 +323,27 @@
                 String name = el.getAttribute("label"); //$NON-NLS-1$

 

                 String exts = null;

-

+                String contentTypes = null;

                 for (IConfigurationElement el2 : el.getChildren())

                 {

                     String ref = el2.getAttribute("dump-type"); //$NON-NLS-1$

                     if (ref != null && done.add(ref))

                     {

                         exts = addExtension(exts, genParser(ref, contentPoint));

+                        if (contentTypes == null)

+                            contentTypes = ref;

+                        else

+                            contentTypes = contentTypes + "," + ref; //$NON-NLS-1$

                     }

 

                     ref = el2.getAttribute("meta-type"); //$NON-NLS-1$

                     if (ref != null && done.add(ref))

                     {

                         exts = addExtension(exts, genParser(ref, contentPoint));

+                        if (contentTypes == null)

+                            contentTypes = ref;

+                        else

+                            contentTypes = contentTypes + "," + ref; //$NON-NLS-1$

                     }

                 }

 

@@ -347,6 +351,8 @@
                 vals.put("id", id); //$NON-NLS-1$

                 vals.put("name", name); //$NON-NLS-1$

                 vals.put("fileExtension", exts); //$NON-NLS-1$

+                if (contentTypes != null)

+                    vals.put("contentTypeBinding", contentTypes); //$NON-NLS-1$

                 String fullid = cont.getName() + "." + id; //$NON-NLS-1$

                 allexts.put(fullid, vals);

             }

diff --git a/plugins/org.eclipse.mat.hprof/plugin.xml b/plugins/org.eclipse.mat.hprof/plugin.xml
index f629700..78965f9 100644
--- a/plugins/org.eclipse.mat.hprof/plugin.xml
+++ b/plugins/org.eclipse.mat.hprof/plugin.xml
Binary files differ
diff --git a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/ChunkedGZIPRandomAccessFile.java b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/ChunkedGZIPRandomAccessFile.java
index fb3f26a..f518750 100644
--- a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/ChunkedGZIPRandomAccessFile.java
+++ b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/ChunkedGZIPRandomAccessFile.java
@@ -19,6 +19,7 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -37,6 +38,8 @@
 import java.util.zip.DeflaterOutputStream;
 import java.util.zip.Inflater;
 
+import org.eclipse.mat.util.FileUtils;
+
 /**
  * This class can be used to get random access to chunked gzipped hprof files like the
  * openjdk can create them. As described in https://tools.ietf.org/html/rfc1952, a gzip
@@ -50,6 +53,8 @@
  */
 public class ChunkedGZIPRandomAccessFile extends RandomAccessFile
 {
+    static final String HPROF_BLOCKSIZE = "HPROF BLOCKSIZE="; //$NON-NLS-1$
+
     // A comparator which compares chunks by their file offset.
     private static FileOffsetComparator fileOffsetComp = new FileOffsetComparator();
 
@@ -407,7 +412,7 @@
 
             // Check if the block size is included in the comment.
             String comment = bos.toString("UTF-8"); //$NON-NLS-1$
-            String expectedPrefix = "HPROF BLOCKSIZE="; //$NON-NLS-1$
+            String expectedPrefix = HPROF_BLOCKSIZE;
 
             if (comment.startsWith(expectedPrefix))
             {
@@ -509,6 +514,108 @@
         cachedOffsets.remove(file.getAbsoluteFile());
     }
 
+    static class ChunkedGZIPOutputStream extends FilterOutputStream
+    {
+        Deflater def = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
+        CRC32 crc = new CRC32();
+        boolean finished = false;
+        int chunkSize = 1024 * 1024;
+        String comment = HPROF_BLOCKSIZE + chunkSize;
+        boolean writtenComment = false;
+        boolean writeHeader = true;
+        byte[] defaultHeader = new byte[] {
+           (byte) 0x1f, (byte) 0x8b, (byte) 8, 0, 0, 0, 0, 0, 0, 0
+        };
+        int left;
+        DeflaterOutputStream dos;
+
+        public ChunkedGZIPOutputStream(OutputStream os)
+        {
+            super(os);
+        }
+        @Override
+        public void write(int b) throws IOException
+        {
+            if (writeHeader)
+            {
+                header();
+            }
+            dos.write(b);
+            if (--left <= 0)
+            {
+                flush();
+            }
+        }
+        @Override
+        public void write(byte b[], int offset, int len) throws IOException
+        {
+            while (len > 0)
+            {
+                if (writeHeader)
+                    header();
+                int len1 = Math.min(len, left);
+                dos.write(b, offset, len1);
+                offset += len1;
+                len -= len1;
+                left -= len1;
+                if (left <= 0)
+                    flush();
+            }
+        }
+        private void header() throws IOException
+        {
+            def.reset();
+            crc.reset();
+
+            // GZipOutputStream does not supports adding a comment, so we have to create
+            // the gzip format by hand.
+            if (writtenComment)
+            {
+                out.write(defaultHeader);
+            }
+            else
+            {
+                out.write(defaultHeader, 0, 3);
+                out.write(16); // We have a comment.
+                out.write(defaultHeader, 4, 6);
+                out.write(comment.getBytes(StandardCharsets.US_ASCII));
+                out.write(0); // Zero terminate comment
+                writtenComment = true;
+            }
+            dos = new DeflaterOutputStream(out, def, 65536);
+            left = chunkSize;
+            writeHeader = false;
+        }
+        @Override
+        public void flush() throws IOException
+        {
+            if (!writeHeader)
+            {
+                dos.finish();
+                int crcVal = (int) crc.getValue();
+                writeInt(crcVal, out);
+                writeInt(chunkSize - left, out);
+                writeHeader = true;
+            }
+            super.flush();
+        }
+        @Override
+        public void close() throws IOException
+        {
+            try
+            {
+                flush();
+                def.finish();
+                dos.close();
+                def.end();
+            }
+            finally 
+            {
+                super.close();
+            }
+        }
+    }
+
     /**
      * Compressed a file to a chunked gzipped file.
      *
@@ -518,11 +625,27 @@
      */
     public static void compressFileChunked(File toCompress, File compressed) throws IOException
     {
+        try (InputStream is = new BufferedInputStream(new FileInputStream(toCompress), 64 * 1024);
+             OutputStream os = new ChunkedGZIPOutputStream(new BufferedOutputStream(new FileOutputStream(compressed), 64 * 1024)))
+        {
+            FileUtils.copy(is, os);
+        }
+    }
+
+    /**
+     * Compressed a file to a chunked gzipped file.
+     *
+     * @param toCompress The file to gzip.
+     * @param compressed The gzipped file.
+     * @throws IOException On error.
+     */
+    public static void compressFileChunked2(File toCompress, File compressed) throws IOException
+    {
         Deflater def = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
         CRC32 crc = new CRC32();
         boolean finished = false;
         int chunkSize = 1024 * 1024;
-        String comment = "HPROF BLOCKSIZE=" + chunkSize; //$NON-NLS-1$
+        String comment = HPROF_BLOCKSIZE + chunkSize;
         boolean writtenComment = false;
         byte[] readBuf = new byte[chunkSize];
         byte[] defaultHeader = new byte[] {
diff --git a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/ExportHprof.java b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/ExportHprof.java
index 3968e34..3dd05e8 100644
--- a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/ExportHprof.java
+++ b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/ExportHprof.java
@@ -1,10 +1,10 @@
 /*******************************************************************************

- * Copyright (c) 2018, 2020 IBM Corporation

+ * Copyright (c) 2018, 2021 IBM Corporation

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -117,6 +117,9 @@
     @Argument(isMandatory = false)

     public boolean compress;

 

+    @Argument(isMandatory = false)

+    public boolean chunked;

+

     public enum RedactType

     {

         NONE("none"), //$NON-NLS-1$

@@ -363,7 +366,10 @@
         long startTime;

         OutputStream outstream = new BufferedOutputStream(new FileOutputStream(output), 1024 * 64);

         if (compress)

-            outstream = new GZIPOutputStream(outstream);

+            if (chunked)

+                outstream = new ChunkedGZIPRandomAccessFile.ChunkedGZIPOutputStream(outstream);

+            else

+                outstream = new GZIPOutputStream(outstream);

         DataOutputStream3 os = new DataOutputStream3(outstream);

         try

         {

diff --git a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JMapHeapDumpProvider.java b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JMapHeapDumpProvider.java
index 9306249..4b2616a 100644
--- a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JMapHeapDumpProvider.java
+++ b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JMapHeapDumpProvider.java
@@ -3,8 +3,8 @@
  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -55,21 +55,26 @@
 public class JMapHeapDumpProvider implements IHeapDumpProvider

 {

 

-	private static final String PLUGIN_ID = "org.eclipse.mat.hprof"; //$NON-NLS-1$

-	private static final String LAST_JDK_DIRECTORY_KEY = JMapHeapDumpProvider.class.getName() + ".lastJDKDir"; //$NON-NLS-1$

-	private static final String LAST_JMAP_JDK_DIRECTORY_KEY = JMapHeapDumpProvider.class.getName() + ".lastJmapJDKDir"; //$NON-NLS-1$

-	static final String FILE_PATTERN = "java_pid{1,number,0}.{2,number,0000}.hprof"; //$NON-NLS-1$

-	static final String FILE_GZ_PATTERN = "java_pid{1,number,0}.{2,number,0000}.hprof.gz"; //$NON-NLS-1$

+    private static final String PLUGIN_ID = "org.eclipse.mat.hprof"; //$NON-NLS-1$

+    private static final String LAST_JDK_DIRECTORY_KEY = JMapHeapDumpProvider.class.getName() + ".lastJDKDir"; //$NON-NLS-1$

+    private static final String LAST_JMAP_JDK_DIRECTORY_KEY = JMapHeapDumpProvider.class.getName() + ".lastJmapJDKDir"; //$NON-NLS-1$

+    static final String FILE_PATTERN = "java_pid{1,number,0}.{2,number,0000}.hprof"; //$NON-NLS-1$

+    static final String FILE_GZ_PATTERN = "java_pid{1,number,0}.{2,number,0000}.hprof.gz"; //$NON-NLS-1$

+    /** Used for the progress monitor for listing processes */

+    private int lastCount = 20;

 

-	@Argument(isMandatory = false, advice = Advice.DIRECTORY)

-	public File jdkHome;

-	@Argument(isMandatory = false, advice = Advice.DIRECTORY)

-	public List<File> jdkList;

+    @Argument(isMandatory = false, advice = Advice.DIRECTORY)

+    public File jdkHome;

+    @Argument(isMandatory = false, advice = Advice.DIRECTORY)

+    public List<File> jdkList;

 

     @Argument(isMandatory = false)

     public boolean defaultCompress;

 

     @Argument(isMandatory = false)

+    public boolean defaultChunked;

+

+    @Argument(isMandatory = false)

     public boolean defaultLive;

 

     public JMapHeapDumpProvider()

@@ -105,101 +110,129 @@
         }

     }

 

-	public File acquireDump(VmInfo info, File preferredLocation, IProgressListener listener) throws SnapshotException

-	{

-	    JmapVmInfo jmapProcessInfo;

-	    if (info instanceof JmapVmInfo)

-	        jmapProcessInfo = (JmapVmInfo) info;

-	    else

-	    {

-	        jmapProcessInfo = new JmapVmInfo(info.getPid(), info.getDescription(), info.isHeapDumpEnabled(), info.getProposedFileName(), info.getHeapDumpProvider());

-	    }

-		listener.beginTask(Messages.JMapHeapDumpProvider_WaitForHeapDump, IProgressMonitor.UNKNOWN);

+    public File acquireDump(VmInfo info, File preferredLocation, IProgressListener listener) throws SnapshotException

+    {

+        JmapVmInfo jmapProcessInfo;

+        if (info instanceof JmapVmInfo)

+            jmapProcessInfo = (JmapVmInfo) info;

+        else

+        {

+            jmapProcessInfo = new JmapVmInfo(info.getPid(), info.getDescription(), info.isHeapDumpEnabled(), info.getProposedFileName(), info.getHeapDumpProvider());

+        }

+        listener.beginTask(Messages.JMapHeapDumpProvider_WaitForHeapDump, IProgressMonitor.UNKNOWN);

+        // jcmd is preferred, but non-live (-all) is not supported on Java 8 

+        final String modules1[] = {"jcmd", "jcmd.exe", "jmap", "jmap.exe"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$

+        final String modules2[] = {"jmap", "jmap.exe", "jcmd", "jcmd.exe"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$

+        final String modules[] = jmapProcessInfo.live ? modules1 : modules2;

+        // just use jmap by default ...

+        String jmap = "jmap"; //$NON-NLS-1$

+        String cmd = jmap;

+        if (jdkHome != null && jdkHome.exists())

+        {

+            for (String mod : modules)

+            {

+                File mod1 = new File(jdkHome.getAbsoluteFile(), "bin"); //$NON-NLS-1$

+                mod1 = new File(mod1, mod);

+                if (mod1.canExecute())

+                {

+                    jmap = mod1.getAbsolutePath();

+                    persistJDKLocation(LAST_JMAP_JDK_DIRECTORY_KEY, jmapProcessInfo.jdkHome.getAbsolutePath());

+                    cmd = mod;

+                    break;

+                }

+            }

+        }

+        // build the line to execute as a String[] because quotes in the name cause

+        // problems on Linux - See bug 313636

+        String[] execLine = cmd.startsWith("jcmd") ?  //$NON-NLS-1$

+                        (jmapProcessInfo.live ?

+                                        new String[] { jmap, // jcmd command

+                                                        String.valueOf(info.getPid()),

+                                                        "GC.heap_dump",  //$NON-NLS-1$

+                                                        preferredLocation.getAbsolutePath()}

+                        :

+                            // -all option is not recognized by Java 8

+                            new String[] { jmap, // jcmd command

+                                            String.valueOf(info.getPid()),

+                                            "GC.heap_dump",  //$NON-NLS-1$

+                                            "-all", //$NON-NLS-1$

+                                            preferredLocation.getAbsolutePath()}

+                                        )

+                        :

+                            new String[] { jmap, // jmap command

+                                            "-dump:" + (jmapProcessInfo.live ? "live," : "") + "format=b,file=" + preferredLocation.getAbsolutePath(), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ 

+                                            String.valueOf(info.getPid()) // pid

+                                        };

 

-		// just use jmap by default ...

-		String jmap = "jmap"; //$NON-NLS-1$

-		// check for previously saved / user defined location 

-		if (jmapProcessInfo.jdkHome != null && jmapProcessInfo.jdkHome.exists())

-		{

-			jmap = jmapProcessInfo.jdkHome.getAbsolutePath() + File.separator + "bin" + File.separator + "jmap"; //$NON-NLS-1$ //$NON-NLS-2$

-			persistJDKLocation(LAST_JMAP_JDK_DIRECTORY_KEY, jmapProcessInfo.jdkHome.getAbsolutePath());

-		}

-		

-		// build the line to execute as a String[] because quotes in the name cause

-		// problems on Linux - See bug 313636

-		String[] execLine = new String[] { jmap, // jmap command

-				"-dump:" + (jmapProcessInfo.live ? "live," : "") + "format=b,file=" + preferredLocation.getAbsolutePath(), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ 

-				String.valueOf(info.getPid()) // pid

-		};

-		

-		// log what gets executed

-		StringBuilder logMessage = new StringBuilder();

-		logMessage.append("Executing { "); //$NON-NLS-1$

-		for (int i = 0; i < execLine.length; i++)

-		{

-			logMessage.append("\"").append(execLine[i]).append("\""); //$NON-NLS-1$ //$NON-NLS-2$

-			if (i < execLine.length - 1) logMessage.append(", "); //$NON-NLS-1$

-		}

-		logMessage.append(" }"); //$NON-NLS-1$

-		

-		Logger.getLogger(getClass().getName()).info(logMessage.toString());

-		Process p = null;

-		try

-		{

-			p = Runtime.getRuntime().exec(execLine);

+        // log what gets executed

+        StringBuilder logMessage = new StringBuilder();

+        logMessage.append("Executing { "); //$NON-NLS-1$

+        for (int i = 0; i < execLine.length; i++)

+        {

+            logMessage.append("\"").append(execLine[i]).append("\""); //$NON-NLS-1$ //$NON-NLS-2$

+            if (i < execLine.length - 1) logMessage.append(", "); //$NON-NLS-1$

+        }

+        logMessage.append(" }"); //$NON-NLS-1$

 

-			StreamCollector error = new StreamCollector(p.getErrorStream());

-			error.start();

-			StreamCollector output = new StreamCollector(p.getInputStream());

-			output.start();

+        Logger.getLogger(getClass().getName()).info(logMessage.toString());

+        listener.subTask(jmap);

+        Process p = null;

+        try

+        {

+            p = Runtime.getRuntime().exec(execLine);

 

-			if (listener.isCanceled()) return null;

+            StreamCollector error = new StreamCollector(p.getErrorStream());

+            error.start();

+            StreamCollector output = new StreamCollector(p.getInputStream());

+            output.start();

 

-			int exitCode = p.waitFor();

-			if (exitCode != 0)

-			{

-				throw new SnapshotException(MessageUtil.format(Messages.JMapHeapDumpProvider_ErrorCreatingDump, exitCode, error.buf.toString()));

-			}

+            if (listener.isCanceled()) return null;

 

-			if (!preferredLocation.exists())

-			{

-				throw new SnapshotException(MessageUtil.format(Messages.JMapHeapDumpProvider_HeapDumpNotCreated, exitCode, output.buf.toString(), error.buf.toString()));

-			}

-		}

-		catch (IOException ioe)

-		{

-			throw new SnapshotException(Messages.JMapHeapDumpProvider_ErrorCreatingDump, ioe);

-		}

-		catch (InterruptedException ie)

-		{

-			throw new SnapshotException(Messages.JMapHeapDumpProvider_ErrorCreatingDump, ie);

-		}

-		finally

-		{

-			if (p != null) p.destroy();

-		}

+            int exitCode = p.waitFor();

+            if (exitCode != 0)

+            {

+                throw new SnapshotException(MessageUtil.format(Messages.JMapHeapDumpProvider_ErrorCreatingDump, exitCode, error.buf.toString(), jmap));

+            }

 

-		if (jmapProcessInfo.compress)

-		{

-		    try

-		    {

-		        preferredLocation = compressFile(preferredLocation, jmapProcessInfo.chunked, listener);

-		    }

-		    catch (IOException e)

-		    {

-		        throw new SnapshotException(Messages.JMapHeapDumpProvider_ErrorCreatingDump, e);

-		    }

-		}

+            if (!preferredLocation.exists())

+            {

+                throw new SnapshotException(MessageUtil.format(Messages.JMapHeapDumpProvider_HeapDumpNotCreated, exitCode, output.buf.toString(), error.buf.toString(), jmap));

+            }

+        }

+        catch (IOException ioe)

+        {

+            throw new SnapshotException(Messages.JMapHeapDumpProvider_ErrorCreatingDump, ioe);

+        }

+        catch (InterruptedException ie)

+        {

+            throw new SnapshotException(Messages.JMapHeapDumpProvider_ErrorCreatingDump, ie);

+        }

+        finally

+        {

+            if (p != null) p.destroy();

+        }

 

-		listener.done();

+        if (jmapProcessInfo.compress)

+        {

+            try

+            {

+                preferredLocation = compressFile(preferredLocation, jmapProcessInfo.chunked, listener);

+            }

+            catch (IOException e)

+            {

+                throw new SnapshotException(Messages.JMapHeapDumpProvider_ErrorCreatingDump, e);

+            }

+        }

 

-		return preferredLocation;

-	}

+        listener.done();

+

+        return preferredLocation;

+    }

 

     File compressFile(File dump, boolean chunked, IProgressListener listener) throws IOException

     {

         listener.subTask(Messages.JMapHeapDumpProvider_CompressingDump);

-        File dumpout = File.createTempFile(dump.getName(),  null, dump.getParentFile());

+        File dumpout = File.createTempFile(dump.getName(), null, dump.getParentFile());

 

         if (chunked)

         {

@@ -209,9 +242,9 @@
         {

             int bufsize = 64 * 1024;

             try (FileInputStream in = new FileInputStream(dump);

-                 InputStream inb = new BufferedInputStream(in, bufsize);

-                 FileOutputStream out = new FileOutputStream(dumpout);

-                 GZIPOutputStream outb = new GZIPOutputStream(out, bufsize))

+                            InputStream inb = new BufferedInputStream(in, bufsize);

+                            FileOutputStream out = new FileOutputStream(dumpout);

+                            GZIPOutputStream outb = new GZIPOutputStream(out, bufsize))

             {

                 byte b[] = new byte[bufsize];

                 for (;;)

@@ -244,154 +277,160 @@
         return dump;

     }

 

-	public List<JmapVmInfo> getAvailableVMs(IProgressListener listener) throws SnapshotException

-	{

-	    listener.beginTask(Messages.JMapHeapDumpProvider_ListProcesses, IProgressListener.UNKNOWN_TOTAL_WORK);

-	    // was something injected from outside?

-	    if (jdkList == null || jdkList.isEmpty())

-	    {

-	        // Repopulate the list

-	        guessJDKFromJDT();

+    public List<JmapVmInfo> getAvailableVMs(IProgressListener listener) throws SnapshotException

+    {

+        listener.beginTask(Messages.JMapHeapDumpProvider_ListProcesses, lastCount);

+        // was something injected from outside?

+        if (jdkList == null || jdkList.isEmpty())

+        {

+            // Repopulate the list

+            guessJDKFromJDT();

             guessJDK();

             guessJDKFromPath();

-	    }

-	    if (jdkHome != null && jdkHome.exists())

-	    {

-	        // If the jdk directory has changed, clear the jmap directory

-	        File old = readSavedLocation(LAST_JDK_DIRECTORY_KEY);

-	        if (!(old != null && jdkHome.getAbsoluteFile().equals(old)))

-	            persistJDKLocation(LAST_JMAP_JDK_DIRECTORY_KEY, null);

-	        persistJDKLocation(LAST_JDK_DIRECTORY_KEY, jdkHome.getAbsolutePath());

-	    }

+        }

+        if (jdkHome != null && jdkHome.exists())

+        {

+            // If the jdk directory has changed, clear the jmap directory

+            File old = readSavedLocation(LAST_JDK_DIRECTORY_KEY);

+            if (!(old != null && jdkHome.getAbsoluteFile().equals(old)))

+                persistJDKLocation(LAST_JMAP_JDK_DIRECTORY_KEY, null);

+            persistJDKLocation(LAST_JDK_DIRECTORY_KEY, jdkHome.getAbsolutePath());

+        }

 

-		List<JmapVmInfo> result = new ArrayList<JmapVmInfo>();

-		List<JmapVmInfo> jvms = LocalJavaProcessesUtils.getLocalVMsUsingJPS(jdkHome);

-		if (jvms != null)

-		{

-		    if (jdkHome == null)

-		        persistJDKLocation(LAST_JDK_DIRECTORY_KEY, null);

-			// try to get jmap specific location for the JDK

-			File jmapJdkHome = readSavedLocation(LAST_JMAP_JDK_DIRECTORY_KEY);

-			if (jmapJdkHome == null) jmapJdkHome = this.jdkHome;

-			

-			for (JmapVmInfo vmInfo : jvms)

-			{

-				//vmInfo.setProposedFileName(defaultCompress ? FILE_GZ_PATTERN : FILE_PATTERN);

-				vmInfo.setHeapDumpProvider(this);

-				vmInfo.jdkHome = jmapJdkHome;

-				vmInfo.compress = defaultCompress;

-				vmInfo.live = defaultLive;

-				result.add(vmInfo);

-			}

-		}

-		listener.done();

-		return result;

-	}

+        List<JmapVmInfo> result = new ArrayList<JmapVmInfo>();

+        List<JmapVmInfo> jvms = LocalJavaProcessesUtils.getLocalVMsUsingJPS(jdkHome, listener);

+        if (jvms != null)

+        {

+            lastCount = jvms.size();

+            if (jdkHome == null)

+                persistJDKLocation(LAST_JDK_DIRECTORY_KEY, null);

+            // try to get jmap specific location for the JDK

+            File jmapJdkHome = readSavedLocation(LAST_JMAP_JDK_DIRECTORY_KEY);

+            if (jmapJdkHome == null) jmapJdkHome = this.jdkHome;

 

-	private void persistJDKLocation(String key, String value)

-	{

-		IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(PLUGIN_ID);

-		if (value == null)

-		    prefs.remove(key);

-		else

-		    prefs.put(key, value);

-		try

-		{

-			prefs.flush();

-		}

-		catch (BackingStoreException e)

-		{

-			// e.printStackTrace();

-			// ignore this exception

-		}

-	}

+            for (JmapVmInfo vmInfo : jvms)

+            {

+                //vmInfo.setProposedFileName(defaultCompress ? FILE_GZ_PATTERN : FILE_PATTERN);

+                vmInfo.setHeapDumpProvider(this);

+                vmInfo.jdkHome = jmapJdkHome;

+                vmInfo.compress = defaultCompress;

+                vmInfo.chunked = defaultChunked;

+                vmInfo.live = defaultLive;

+                result.add(vmInfo);

+            }

+        }

+        listener.done();

+        return result;

+    }

 

-	private File readSavedLocation(String key)

-	{

-		String lastDir = Platform.getPreferencesService().getString(PLUGIN_ID, key, "", null); //$NON-NLS-1$

-		if (lastDir != null && !lastDir.trim().equals("")) //$NON-NLS-1$

-		{

-			return new File(lastDir);

-		}

-		return null;

-	}

+    private void persistJDKLocation(String key, String value)

+    {

+        IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(PLUGIN_ID);

+        if (value == null)

+            prefs.remove(key);

+        else

+            prefs.put(key, value);

+        try

+        {

+            prefs.flush();

+        }

+        catch (BackingStoreException e)

+        {

+            // e.printStackTrace();

+            // ignore this exception

+        }

+    }

 

-	private File guessJDKFromJDT()

-	{

-	    IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode("org.eclipse.jdt.launching"); //$NON-NLS-1$

-	    if (prefs == null)

-	        return null;

-	    String s1 = prefs.get("org.eclipse.jdt.launching.PREF_VM_XML", null); //$NON-NLS-1$

-	    if (s1 == null)

-	        return null;

-	    try

-	    {

-	        List<File> paths = parseJDTvmSettings(s1);

-	        jdkList = paths;

-	        if (paths.size() >= 1)

-	            return paths.get(0);

-	        return null;

-	    }

-	    catch (IOException e)

-	    {

-	        return null;

-	    }

-	}

-

-	private File guessJDK()

-	{

-	    String modules[] = {"jps", "jps.exe"}; //$NON-NLS-1$ //$NON-NLS-2$

-	    String javaHomeProperty = System.getProperty("java.home"); //$NON-NLS-1$

-	    File parentFolder = new File(javaHomeProperty).getParentFile();

-	    File binDir = new File(parentFolder, "bin"); //$NON-NLS-1$

-	    if (binDir.exists())

-	    {

-	        // See if jps is present

-	        for (String mod : modules)

-	        {

-	            File dll = new File(binDir, mod);

-	            if (dll.canExecute())

-	            {

-	                if (jdkList != null && !jdkList.contains(parentFolder))

-	                    jdkList.add(parentFolder);

-	                return parentFolder;

-	            }

-	        }

-	    }

+    private File readSavedLocation(String key)

+    {

+        String lastDir = Platform.getPreferencesService().getString(PLUGIN_ID, key, "", null); //$NON-NLS-1$

+        if (lastDir != null && !lastDir.trim().equals("")) //$NON-NLS-1$

+        {

+            return new File(lastDir);

+        }

         return null;

-	}

+    }

 

-	private File guessJDKFromPath()

-	{

-	    File jdkHome = null;

-	    String modules[] = {"jps", "jps.exe"}; //$NON-NLS-1$ //$NON-NLS-2$

-	    String path = System.getenv("PATH"); //$NON-NLS-1$

-	    if (path != null)

-	    {

-	        for (String p : path.split(File.pathSeparator))

-	        {

-	            File dir = new File(p);

-	            File parentDir = dir.getParentFile();

-	            // See if jps is present

-	            for (String mod : modules)

-	            {

-	                File dll = new File(dir, mod);

-	                if (dll.canExecute())

-	                {

-	                    if (parentDir != null && parentDir.getName().equals("bin")) //$NON-NLS-1$

-	                    {

-	                        File home = parentDir.getParentFile();

-	                        if (jdkHome == null)

-	                            jdkHome = home;

-	                        if (jdkList != null && !jdkList.contains(home))

-	                            jdkList.add(home);

-	                    }

-	                }

-	            }

-	        }

-	    }

-	    return jdkHome;

-	}

+    private File guessJDKFromJDT()

+    {

+        IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode("org.eclipse.jdt.launching"); //$NON-NLS-1$

+        if (prefs == null)

+            return null;

+        String s1 = prefs.get("org.eclipse.jdt.launching.PREF_VM_XML", null); //$NON-NLS-1$

+        if (s1 == null)

+            return null;

+        try

+        {

+            List<File> paths = parseJDTvmSettings(s1);

+            jdkList = paths;

+            if (paths.size() >= 1)

+                return paths.get(0);

+            return null;

+        }

+        catch (IOException e)

+        {

+            return null;

+        }

+    }

+

+    private static final String modules[] = {"jcmd", "jcmd.exe", "jps", "jps.exe"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$

+    private File guessJDK()

+    {

+        String javaHomeProperty = System.getProperty("java.home"); //$NON-NLS-1$

+        File folders[] = new File[2];

+        folders[0] = new File(javaHomeProperty);

+        folders[1] = folders[0].getParentFile();

+        for (File parentFolder : folders)

+        {

+            File binDir = new File(parentFolder, "bin"); //$NON-NLS-1$

+            if (binDir.exists())

+            {

+                // See if jps is present

+                for (String mod : modules)

+                {

+                    File dll = new File(binDir, mod);

+                    if (dll.canExecute())

+                    {

+                        if (jdkList != null && !jdkList.contains(parentFolder))

+                            jdkList.add(parentFolder);

+                        return parentFolder;

+                    }

+                }

+            }

+        }

+        return null;

+    }

+

+    private File guessJDKFromPath()

+    {

+        File jdkHome = null;

+        String path = System.getenv("PATH"); //$NON-NLS-1$

+        if (path != null)

+        {

+            for (String p : path.split(File.pathSeparator))

+            {

+                File dir = new File(p);

+                File parentDir = dir.getParentFile();

+                // See if jps is present

+                for (String mod : modules)

+                {

+                    File dll = new File(dir, mod);

+                    if (dll.canExecute())

+                    {

+                        if (parentDir != null && parentDir.getName().equals("bin")) //$NON-NLS-1$

+                        {

+                            File home = parentDir.getParentFile();

+                            if (jdkHome == null)

+                                jdkHome = home;

+                            if (jdkList != null && !jdkList.contains(home))

+                                jdkList.add(home);

+                        }

+                    }

+                }

+            }

+        }

+        return jdkHome;

+    }

 

     // //////////////////////////////////////////////////////////////

     // XML reading

@@ -416,10 +455,16 @@
                 File dir = new File(homedir, "bin"); //$NON-NLS-1$

                 if (dir.exists())

                 {

-                    File jps1 = new File(dir, "jps"); //$NON-NLS-1$

-                    File jps2 = new File(dir, "jps.exe"); //$NON-NLS-1$

-                    if (jps1.canExecute() || jps2.canExecute())

-                        homes.add(homedir);

+                    // See if jps is present

+                    for (String mod : modules)

+                    {

+                        File jps = new File(dir, mod);

+                        if (jps.canExecute())

+                        {

+                            homes.add(homedir);

+                            break;

+                        }

+                    }

                 }

             }

             return homes;

diff --git a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JmapVmInfo.java b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JmapVmInfo.java
index 474ddfe..a27898c 100644
--- a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JmapVmInfo.java
+++ b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JmapVmInfo.java
@@ -3,8 +3,8 @@
  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -27,15 +27,15 @@
 	@Argument(isMandatory = false, advice = Advice.DIRECTORY)

 	public File jdkHome;

 

-    @Argument

+	@Argument(isMandatory = false)

     public boolean compress;

 

-    @Argument

-    public boolean live;

-

-    // No @Argument, since currently only used in tests.

+    @Argument(isMandatory = false)

     public boolean chunked;

 

+	@Argument(isMandatory = false)

+    public boolean live;

+

 	public JmapVmInfo(int pid, String description, boolean heapDumpEnabled, String proposedFileName, IHeapDumpProvider heapDumpProvider)

 	{

 		super(pid, description, heapDumpEnabled, proposedFileName, heapDumpProvider);

diff --git a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/LocalJavaProcessesUtils.java b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/LocalJavaProcessesUtils.java
index bdf26b3..2bdda1e 100644
--- a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/LocalJavaProcessesUtils.java
+++ b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/LocalJavaProcessesUtils.java
@@ -3,8 +3,8 @@
  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -26,132 +26,163 @@
 

 import org.eclipse.mat.SnapshotException;

 import org.eclipse.mat.hprof.Messages;

+import org.eclipse.mat.util.IProgressListener;

+import org.eclipse.mat.util.MessageUtil;

 

 public class LocalJavaProcessesUtils

 {

-    static List<JmapVmInfo> getLocalVMsUsingJPS(File jdkHome) throws SnapshotException

+    static List<JmapVmInfo> getLocalVMsUsingJPS(File jdkHome, IProgressListener listener) throws SnapshotException

     {

+        final String modules[] = {"jcmd", "jcmd.exe", "jps", "jps.exe"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$

         String jps = "jps"; //$NON-NLS-1$

+        String cmd = jps;

         if (jdkHome != null && jdkHome.exists())

         {

-            jps = jdkHome.getAbsolutePath() + File.separator + "bin" + File.separator + "jps"; //$NON-NLS-1$ //$NON-NLS-2$

-        }

-

-        StreamCollector error = null;

-        StreamCollector output = null;

-        Process p = null;

-        try

-        {

-            String encoding = System.getProperty("file.encoding", "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$

-            p = Runtime.getRuntime().exec(new String[]{jps, "-m", "-l", "-J-Dfile.encoding="+encoding}); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$

-            error = new StreamCollector(p.getErrorStream(), encoding);

-            error.start();

-            output = new StreamCollector(p.getInputStream(), encoding);

-            output.start();

-

-            int exitVal = p.waitFor();

-

-            if (exitVal != 0) return null;

-

-            List<JmapVmInfo> vms = new ArrayList<JmapVmInfo>();

-            int jpsProcesses = 0;

-            String jpssig = "Jps -m -l"; //$NON-NLS-1$

-            StringTokenizer tok = new StringTokenizer(output.buf.toString(), "\r\n"); //$NON-NLS-1$

-            while (tok.hasMoreTokens())

+            for (String mod : modules)

             {

-                String token = tok.nextToken();

-

-                // System.err.println(token);

-                JmapVmInfo info = parseJPSLine(token);

-                if (info != null)

+                File mod1 = new File(jdkHome.getAbsoluteFile(), "bin"); //$NON-NLS-1$

+                mod1 = new File(mod1, mod);

+                if (mod1.canExecute())

                 {

-                    vms.add(info);

-                    if (info.getDescription().contains(jpssig))

-                        ++jpsProcesses;

+                    jps = mod1.getAbsolutePath();

+                    cmd = mod;

+                    break;

                 }

             }

-            // Mark the jps process as not suitable for dumps

-            if (jpsProcesses == 1)

+        }

+        String encoding = System.getProperty("file.encoding", "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$

+        String cmds[] = cmd.startsWith("jcmd") ?  //$NON-NLS-1$

+                        new String[]{jps, "-l", "-J-Dfile.encoding="+encoding} //$NON-NLS-1$//$NON-NLS-2$

+        : new String[]{jps, "-l", "-J-Dfile.encoding="+encoding}; //$NON-NLS-1$//$NON-NLS-2$

+                        listener.subTask(jps);

+                        StreamCollector error = null;

+                        StreamCollector output = null;

+                        Process p = null;

+                        try

+                        {

+                            p = Runtime.getRuntime().exec(cmds);

+                            error = new StreamCollector(p.getErrorStream(), encoding);

+                            error.start();

+                            output = new StreamCollector(p.getInputStream(), encoding, listener);

+                            output.start();

+

+                            int exitVal = p.waitFor();

+

+                            if (exitVal != 0) return null;

+

+                            List<JmapVmInfo> vms = new ArrayList<JmapVmInfo>();

+                            int jpsProcesses = 0;

+                            String jpssig = cmd.startsWith("jcmd") ? "JCmd -l" : "Jps -m -l"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

+                            StringTokenizer tok = new StringTokenizer(output.buf.toString(), "\r\n"); //$NON-NLS-1$

+                            while (tok.hasMoreTokens())

+                            {

+                                String token = tok.nextToken();

+

+                                // System.err.println(token);

+                                JmapVmInfo info = parseJPSLine(token);

+                                if (info != null)

+                                {

+                                    vms.add(info);

+                                    if (info.getDescription().contains(jpssig))

+                                        ++jpsProcesses;

+                                }

+                            }

+                            // Mark the jps process as not suitable for dumps

+                            if (jpsProcesses == 1)

+                            {

+                                for (JmapVmInfo info : vms)

+                                {

+                                    if (info.getDescription().contains(jpssig))

+                                    {

+                                        info.setHeapDumpEnabled(false);

+                                        break;

+                                    }

+                                }

+                            }

+                            return vms;

+                        }

+                        catch (IOException ioe)

+                        {

+                            throw new SnapshotException(MessageUtil.format(Messages.LocalJavaProcessesUtils_ErrorGettingProcessListJPS, jps), ioe);

+                        }

+                        catch (InterruptedException ie)

+                        {

+                            throw new SnapshotException(MessageUtil.format(Messages.LocalJavaProcessesUtils_ErrorGettingProcessListJPS, jps), ie);

+                        }

+                        finally

+                        {

+                            if (p != null)

+                                p.destroy();

+                        }

+    }

+

+    private static JmapVmInfo parseJPSLine(String line)

+    {

+        int firstSpaceIdx = line.indexOf(' ');

+        if (firstSpaceIdx == -1) return null;

+        int pid = Integer.parseInt(line.substring(0, firstSpaceIdx));

+        String description = line.substring(firstSpaceIdx + 1);

+        return new JmapVmInfo(pid, description, true, null, null);

+    }

+

+    static class StreamCollector extends Thread

+    {

+        InputStream is;

+        StringBuilder buf;

+        String encoding;

+        IProgressListener listener;

+        int count;

+

+        StreamCollector(InputStream is)

+        {

+            this(is, System.getProperty("file.encoding", "UTF-8"), null);  //$NON-NLS-1$//$NON-NLS-2$

+        }

+

+        StreamCollector(InputStream is, String encoding)

+        {

+            this(is, encoding, null);

+        }

+

+        StreamCollector(InputStream is, String encoding, IProgressListener listener)

+        {

+            this.is = is;

+            this.buf = new StringBuilder();

+            this.encoding = encoding;

+            this.listener = listener;

+        }

+

+        public void run()

+        {

+            InputStreamReader isr = null;

+            try

             {

-                for (JmapVmInfo info : vms)

+                isr = new InputStreamReader(is, encoding);

+                BufferedReader br = new BufferedReader(isr);

+                String line = null;

+                while ((line = br.readLine()) != null)

                 {

-                    if (info.getDescription().contains(jpssig))

+                    buf.append(line).append("\r\n"); //$NON-NLS-1$

+                    if (listener != null)

                     {

-                        info.setHeapDumpEnabled(false);

-                        break;

+                        listener.worked(1);

                     }

                 }

             }

-            return vms;

-        }

-        catch (IOException ioe)

-        {

-            throw new SnapshotException(Messages.LocalJavaProcessesUtils_ErrorGettingProcessListJPS, ioe);

-        }

-        catch (InterruptedException ie)

-        {

-            throw new SnapshotException(Messages.LocalJavaProcessesUtils_ErrorGettingProcessListJPS, ie);

-        }

-        finally

-        {

-            if (p != null)

-                p.destroy();

+            catch (IOException ioe)

+            {

+                Logger.getLogger(getClass().getName()).log(Level.SEVERE, Messages.LocalJavaProcessesUtils_ErrorGettingProcesses, ioe);

+            }

+            finally

+            {

+                if (isr != null) try

+                {

+                    isr.close();

+                }

+                catch (IOException e)

+                {

+                    // ignore this

+                }

+            }

         }

     }

-

-	private static JmapVmInfo parseJPSLine(String line)

-	{

-		int firstSpaceIdx = line.indexOf(' ');

-		if (firstSpaceIdx == -1) return null;

-		int pid = Integer.parseInt(line.substring(0, firstSpaceIdx));

-		String description = line.substring(firstSpaceIdx + 1);

-		return new JmapVmInfo(pid, description, true, null, null);

-	}

-

-	static class StreamCollector extends Thread

-	{

-		InputStream is;

-		StringBuilder buf;

-		String encoding;

-

-		StreamCollector(InputStream is)

-		{

-			this(is, System.getProperty("file.encoding", "UTF-8"));  //$NON-NLS-1$//$NON-NLS-2$

-		}

-		

-	      StreamCollector(InputStream is, String encoding)

-	        {

-	            this.is = is;

-	            this.buf = new StringBuilder();

-	            this.encoding = encoding;

-	        }

-

-		public void run()

-		{

-			InputStreamReader isr = null;

-			try

-			{

-				isr = new InputStreamReader(is, encoding);

-				BufferedReader br = new BufferedReader(isr);

-				String line = null;

-				while ((line = br.readLine()) != null)

-					buf.append(line).append("\r\n"); //$NON-NLS-1$

-			}

-			catch (IOException ioe)

-			{

-				Logger.getLogger(getClass().getName()).log(Level.SEVERE, Messages.LocalJavaProcessesUtils_ErrorGettingProcesses, ioe);

-			}

-			finally

-			{

-				if (isr != null) try

-				{

-					isr.close();

-				}

-				catch (IOException e)

-				{

-					// ignore this

-				}

-			}

-		}

-	}

 }

diff --git a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/annotations.properties b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/annotations.properties
index 9787594..e13ad1b 100644
--- a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/annotations.properties
+++ b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/annotations.properties
@@ -1,29 +1,34 @@
-###############################################################################
-# Copyright (c) 2010, 2021 SAP AG, IBM Corporation and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Eclipse Public License 2.0
-# which accompanies this distribution, and is available at
-# https://www.eclipse.org/legal/epl-2.0/
-#
-# SPDX-License-Identifier: EPL-2.0
-#
-# Contributors:
-#     SAP AG - initial API and implementation
-#     IBM Corporation/Andrew Johnson - additional help, gzip
-###############################################################################
-# JMapHeapDumpProvider
-JMapHeapDumpProvider.name = HPROF jmap dump provider
-JMapHeapDumpProvider.help = Generates a binary HPROF heap dump using jmap.
-JMapHeapDumpProvider.jdkHome.help = JDK directory\n\
-This heap dump provider needs a JDK from which it can call jps and jmap. If Memory Analyzer \
-is started with a JRE one may need to configure the JDK for the heap dump provider. \n\
-If no JDK is specified the tool will try calling just 'jps' and 'jmap'.
-JMapHeapDumpProvider.jdkList.help = Paths to possible JDK directories. Not used \
-directly but can be copied and pasted into the 'jdkhome' field. \
-Clear the list to refresh.
-JMapHeapDumpProvider.defaultCompress.help = Whether to compress the generated dump with gzip, to save disk space at the possible cost of a longer load time.
-JMapHeapDumpProvider.defaultLive.help = Whether to only dump live objects by doing a garbage collection before dumping the heap.
-# JmapVmInfo
-JmapVmInfo.jdkHome.name = Configuration for generation of a binary HPROF heap dump using jmap.
-JmapVmInfo.jdkHome.help = Location of the appropriate JDK
-JmapVmInfo.compress.help = Whether to compress the generated dump with gzip, to save disk space at the possible cost of a longer load time.
+###############################################################################

+# Copyright (c) 2010, 2021 SAP AG, IBM Corporation and others.

+# All rights reserved. This program and the accompanying materials

+# are made available under the terms of the Eclipse Public License 2.0

+# which accompanies this distribution, and is available at

+# https://www.eclipse.org/legal/epl-2.0/

+#

+# SPDX-License-Identifier: EPL-2.0

+#

+# Contributors:

+#     SAP AG - initial API and implementation

+#     IBM Corporation/Andrew Johnson - additional help, gzip

+###############################################################################

+# JMapHeapDumpProvider

+JMapHeapDumpProvider.name = HPROF jmap dump provider

+JMapHeapDumpProvider.help = Generates a binary HPROF heap dump using jmap or jcmd.

+JMapHeapDumpProvider.jdkHome.help = JDK directory\n\

+This heap dump provider needs a JDK from which it can call jps and jmap or jcmd. If Memory Analyzer \

+is started with a JRE one may need to configure the JDK for the heap dump provider. \n\

+If no JDK is specified the tool will try calling just 'jps' and 'jmap' or 'jcmd'.

+JMapHeapDumpProvider.jdkList.help = Paths to possible JDK directories. Not used \

+directly but can be copied and pasted into the 'jdkhome' field. \

+Clear the list to refresh.

+JMapHeapDumpProvider.defaultCompress.help = Whether to compress the generated dump with gzip, to save disk space at the possible cost of a longer load time.

+JMapHeapDumpProvider.defaultChunked.help = Whether, when compressing the generated dump, to do so in chunks, for faster loading than regular compressed files.

+JMapHeapDumpProvider.defaultLive.help = Whether to only dump live objects by doing a garbage collection before dumping the heap.\n\

+Required when using some versions of jcmd.

+# JmapVmInfo

+JmapVmInfo.jdkHome.name = Configuration for generation of a binary HPROF heap dump using jmap or jcmd.

+JmapVmInfo.jdkHome.help = Location of the appropriate JDK

+JmapVmInfo.compress.help = Whether to compress the generated dump with gzip, to save disk space at the possible cost of a longer load time.

+JmapVmInfo.chunked.help = Whether, when compressing the generated dump, to do so in chunks, for faster loading than regular compressed files.

+JmapVmInfo.live.help = Whether to only dump live objects by doing a garbage collection before dumping the heap.\n\

+Required when using some versions of jcmd.
\ No newline at end of file
diff --git a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/annotations.properties b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/annotations.properties
index 7f4692e..afe67a0 100644
--- a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/annotations.properties
+++ b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/annotations.properties
@@ -1,10 +1,10 @@
 ###############################################################################

-# Copyright (c) 2018,2019 IBM Corporation.

+# Copyright (c) 2018,2021 IBM Corporation.

 # All rights reserved. This program and the accompanying materials

 # are made available under the terms of the Eclipse Public License 2.0

 # which accompanies this distribution, and is available at

-# https://www.eclipse.org/legal/epl-2.0/
-#
+# https://www.eclipse.org/legal/epl-2.0/

+#

 # SPDX-License-Identifier: EPL-2.0

 #

 # Contributors:

@@ -18,6 +18,7 @@
 can be used for all, so that the exported HPROF files use the same obfuscated names for the same class in each file.

 ExportHprof.output.help = The file name of the new HPROF dump.

 ExportHprof.compress.help = Whether to compress the generated dump, to save disk space at the possible cost of a longer load time.

+ExportHprof.chunked.help = Whether, when compressing the generated dump, to do so in chunks, for faster loading than regular compressed files.

 ExportHprof.redact.help = Whether to redact certain field and array types.\n\

 NONE exports all field and array values unchanged.\n\

 NAMES obfuscates byte and char array contents to match obfuscated class and field names.\n\

diff --git a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/messages.properties b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/messages.properties
index a8b5c6b..2381af1 100644
--- a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/messages.properties
+++ b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/messages.properties
@@ -1,10 +1,10 @@
 ###############################################################################

-# Copyright (c) 2010, 2020 SAP AG and others.

+# Copyright (c) 2010, 2021 SAP AG and others.

 # All rights reserved. This program and the accompanying materials

 # are made available under the terms of the Eclipse Public License 2.0

 # which accompanies this distribution, and is available at

-# https://www.eclipse.org/legal/epl-2.0/
-#
+# https://www.eclipse.org/legal/epl-2.0/

+#

 # SPDX-License-Identifier: EPL-2.0

 #

 # Contributors:

@@ -60,13 +60,13 @@
 IPositionInputStream_mark=mark

 IPositionInputStream_reset=reset

 IPositionInputStream_seek=seek

-JMapHeapDumpProvider_ErrorCreatingDump=Error creating heap dump. jmap exit code {0}\r\n{1}

-JMapHeapDumpProvider_HeapDumpNotCreated=Heap dump file was not created. jmap exit code = {0}\r\nstdout:\r\n{1}\r\nstderr:\r\n{2}

+JMapHeapDumpProvider_ErrorCreatingDump=Error creating heap dump. {2} exit code {0}\r\n{1}

+JMapHeapDumpProvider_HeapDumpNotCreated=Heap dump file was not created. {3} exit code = {0}\r\nstdout:\r\n{1}\r\nstderr:\r\n{2}

 JMapHeapDumpProvider_WaitForHeapDump=Waiting while the heap dump is written to the disk

-JMapHeapDumpProvider_ListProcesses=Listing VMs using jps

+JMapHeapDumpProvider_ListProcesses=Listing VMs using jps or jcmd

 JMapHeapDumpProvider_CompressingDump=Compressing heap dump

 LocalJavaProcessesUtils_ErrorGettingProcesses=Error getting list of processes

-LocalJavaProcessesUtils_ErrorGettingProcessListJPS=Error getting Java processes list with 'jps'. Try to configure a JDK for the HPROF jmap provider

+LocalJavaProcessesUtils_ErrorGettingProcessListJPS=Error getting Java processes list with '{0}'. Try to configure a JDK for the HPROF jmap provider

 Pass1Parser_DetectedCompressedReferences=Detected compressed references, because with uncompressed 64-bit references the array at 0x{0} would overlap the array at 0x{1}

 Pass1Parser_Error_IllegalRecordLength=Illegal record length {0} at 0x{1} for record type 0x{2} at 0x{3}

 Pass1Parser_Error_IllegalType=Illegal primitive object array type

diff --git a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/BaseProvider.java b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/BaseProvider.java
index 16a572e..ebba802 100644
--- a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/BaseProvider.java
+++ b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/BaseProvider.java
@@ -1,10 +1,10 @@
 /*******************************************************************************

- * Copyright (c) 2010, 2019 IBM Corporation

+ * Copyright (c) 2010, 2021 IBM Corporation

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -39,13 +39,13 @@
     @Argument

     public DumpType defaultType = DumpType.SYSTEM;

 

-    @Argument

+    @Argument(isMandatory = false)

     public boolean defaultLive = false;

 

-    @Argument

+    @Argument(isMandatory = false)

     public boolean defaultCompress = false;

 

-    @Argument

+    @Argument(isMandatory = false)

     public boolean listAttach = true;

     

     @Argument

diff --git a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/HprofDumpProvider.java b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/HprofDumpProvider.java
index f33fdc0..d3db613 100644
--- a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/HprofDumpProvider.java
+++ b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/HprofDumpProvider.java
@@ -1,10 +1,10 @@
 /*******************************************************************************

- * Copyright (c) 2018,2019 IBM Corporation

+ * Copyright (c) 2018,2021 IBM Corporation

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -84,7 +84,7 @@
 

     File compressFile(File preferredDump, File dump, IProgressListener listener) throws IOException

     {

-        File dumpout = preferredDump.equals(dump) ? 

+        File dumpout = preferredDump.getCanonicalFile().equals(dump.getCanonicalFile()) ? 

                        File.createTempFile(dump.getName(),  null, dump.getParentFile())

                      : preferredDump;

         listener.subTask(Messages.getString("IBMDumpProvider.CompressingDump")); //$NON-NLS-1$

@@ -119,9 +119,9 @@
         }

         if (dump.delete())

         {

-            if (!dumpout.equals(preferredDump) && !dumpout.renameTo(preferredDump))

+            if (!dumpout.getCanonicalFile().equals(preferredDump.getCanonicalFile()) && !dumpout.renameTo(preferredDump))

             {

-                throw new IOException(dump.getPath());

+                throw new IOException(preferredDump.getPath());

             }

         }

         else

diff --git a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMExecDumpProvider.java b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMExecDumpProvider.java
index 4c645f2..db32a9e 100644
--- a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMExecDumpProvider.java
+++ b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMExecDumpProvider.java
@@ -1,10 +1,10 @@
 /*******************************************************************************

- * Copyright (c) 2010, 2020 IBM Corporation

+ * Copyright (c) 2010, 2021 IBM Corporation

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -61,6 +61,7 @@
     private static final String PLUGIN_ID = "org.eclipse.mat.ibmdump"; //$NON-NLS-1$

     private static final String JAVA_EXEC = "java"; //$NON-NLS-1$

     private static final String JAVA_EXEC_WINDOWS = "java.exe"; //$NON-NLS-1$

+    private static final String JCMD = "jcmd"; //$NON-NLS-1$

     private static boolean abort = false;

     private int lastCount = 20;

 

@@ -102,24 +103,59 @@
         String vm = info2.getPidName();

         try

         {

-            String jar = getExecJar().getAbsolutePath();

             final String execPath = info2.javaexecutable.getPath();

             List<String> args = new ArrayList<String>(9);

             args.add(execPath);

-            args.add(encodingOpt);

-            if (info2.vmoptions != null)

+            if (info2.javaexecutable.getName().startsWith(JCMD))

             {

-                args.addAll(Arrays.asList(info2.vmoptions));

+                args.add("-J" + encodingOpt); //$NON-NLS-1$

+                if (info2.vmoptions != null)

+                {

+                    for (String arg : info2.vmoptions)

+                    {

+                        args.add("-J" + arg); //$NON-NLS-1$

+                    }

+                }

+                args.add(vm);

+                switch (info2.type)

+                {

+                    case HEAP:

+                        args.add("Dump.heap"); //$NON-NLS-1$

+                        break;

+                    case HPROF:

+                        args.add("GC.heap_dump"); //$NON-NLS-1$

+                        if (!info2.live)

+                            args.add("-all"); //$NON-NLS-1$

+                        break;

+                    case JAVA:

+                        args.add("Dump.java"); //$NON-NLS-1$

+                        break;

+                    case SYSTEM:

+                        args.add("Dump.system"); //$NON-NLS-1$

+                        break;

+                    default:

+                        break;

+                }

+                args.add(preferredLocation.getAbsolutePath());

             }

-            args.add("-jar"); //$NON-NLS-1$

-            args.add(jar);

-            args.add(info2.type.toString());

-            args.add(vm);

-            args.add(Boolean.toString(info2.live));

-            args.add(Boolean.toString(info2.compress));

-            args.add(preferredLocation.getAbsolutePath());

-            if (info2.dumpdir != null)

-                args.add(info2.dumpdir.getAbsolutePath());

+            else

+            {

+                args.add(encodingOpt);

+                if (info2.vmoptions != null)

+                {

+                    args.addAll(Arrays.asList(info2.vmoptions));

+                }

+                args.add("-jar"); //$NON-NLS-1$

+                String jar = getExecJar().getAbsolutePath();

+                args.add(jar);

+                args.add(info2.type.toString());

+                args.add(vm);

+                args.add(Boolean.toString(info2.live));

+                args.add(Boolean.toString(info2.compress));

+                args.add(preferredLocation.getAbsolutePath());

+                if (info2.dumpdir != null)

+                    args.add(info2.dumpdir.getAbsolutePath());

+            }

             pb.command(args);

             p = pb.start();

             StringBuffer err = new StringBuffer();

@@ -181,13 +217,57 @@
                             info.setHeapDumpEnabled(false);

                         }

                         throw new IOException(MessageUtil.format(Messages

-                                    .getString("IBMExecDumpProvider.ReturnCode"), execPath, rc, err.toString())); //$NON-NLS-1$

+                                    .getString("IBMExecDumpProvider.ReturnCode"), args, rc, err.toString())); //$NON-NLS-1$

                     }

                     String ss[] = in.toString().split("[\\n\\r]+"); //$NON-NLS-1$

                     String filename = ss[0];

+                    if (info2.javaexecutable.getName().startsWith(JCMD))

+                    {

+                        // OpenJDK

+                        if (filename.matches("^[0-9]+:$")) //$NON-NLS-1$

+                        {

+                            filename = preferredLocation.getAbsolutePath();

+                        }

+                        else

+                        {

+                            // From J9 jcmd.exe

+                            filename = filename.replaceFirst("^Dump written to ", ""); //$NON-NLS-1$ //$NON-NLS-2$

+                        }

+                    }

                     listener.done();

-                    final File file = new File(filename);

-                    if (!file.canRead()) { throw new FileNotFoundException(filename); }

+                    File file = new File(filename);

+                    if (!file.canRead())

+                    {

+                        // Does it looks like an error message?

+                        if (err.length() > 0 || ss.length > 1)

+                        {

+                            throw new IOException(MessageUtil.format(Messages

+                                            .getString("IBMExecDumpProvider.ReturnCode"), args, rc, err.toString() +"\n" + in.toString())); //$NON-NLS-1$ //$NON-NLS-2$

+                        }

+                        else

+                        {

+                            throw new FileNotFoundException(filename);

+                        }

+                    }

+                    if (info2.javaexecutable.getName().startsWith(JCMD))

+                    {

+                        IBMDumpProvider help1 = new IBMDumpProvider();

+                        IBMDumpProvider helper = help1.getDumpProvider(info2);

+                        List<File>dumps = Collections.singletonList(file);

+                        File javahome = javaexecutable.getParentFile();

+                        if (javahome != null)

+                            javahome = javahome.getParentFile();

+                        try

+                        {

+                            file = helper.jextract(preferredLocation, info2.compress, dumps, file.getParentFile(), javahome, listener);

+                        }

+                        catch (InterruptedException e)

+                        {

+                            listener.sendUserMessage(Severity.WARNING, Messages.getString("IBMDumpProvider.Interrupted"), e); //$NON-NLS-1$

+                            throw new SnapshotException(Messages.getString("IBMDumpProvider.Interrupted"), e); //$NON-NLS-1$

+                        }

+                        return file;

+                    }

                     return file;

                 }

                 finally

@@ -534,18 +614,34 @@
         final String execPath = javaExec.getPath();

         try

         {

-            String jar = getExecJar().getAbsolutePath();

             List<String> args = new ArrayList<String>(4);

             args.add(execPath);

-            args.add(encodingOpt);

-            if (vmoptions != null)

+            boolean useJcmd = javaExec.getName().startsWith(JCMD);

+            if (useJcmd)

             {

-                args.addAll(Arrays.asList(vmoptions));

+                args.add("-J" + encodingOpt); //$NON-NLS-1$

+                if (vmoptions != null)

+                {

+                    for (String arg : vmoptions)

+                    {

+                        args.add("-J" + arg); //$NON-NLS-1$

+                    }

+                }

+                args.add("-l"); //$NON-NLS-1$

             }

-            args.add("-jar"); //$NON-NLS-1$

-            args.add(jar);

-            // Verbose listing?

-            args.add(Boolean.toString(listAttach));

+            else

+            {

+                args.add(encodingOpt);

+                if (vmoptions != null)

+                {

+                    args.addAll(Arrays.asList(vmoptions));

+                }

+                args.add("-jar"); //$NON-NLS-1$

+                String jar = getExecJar().getAbsolutePath();

+                args.add(jar);

+                // Verbose listing?

+                args.add(Boolean.toString(listAttach));

+            }

             pb.command(args);

             p = pb.start();

             StringBuffer err = new StringBuffer();

@@ -562,6 +658,11 @@
                         while (os.ready())

                         {

                             in.append((char) os.read());

+                            if (useJcmd)

+                            {

+                                listener.worked(1);

+                                ++count;

+                            }

                         }

                         while (es.ready())

                         {

@@ -606,7 +707,7 @@
                         if (s2.length >= 5)

                         {

                             // Exclude the helper process

-                            if (!s2[5].contains(getExecJar().getName()))

+                            if (execJar == null || !s2[5].contains(execJar.getName()))

                             {

                                 boolean enableDump = Boolean.parseBoolean(s2[1]);

                                 IBMExecVmInfo ifo = new IBMExecVmInfo(s2[0], s2[5], enableDump, null, this);

@@ -634,6 +735,22 @@
                                 ar.add(ifo);

                             }

                         }

+                        else

+                        {

+                            // JCmd output

+                            // pid more process details

+                            s2 = s.split(" ", 2); //$NON-NLS-1$

+                            if (s2.length == 2 && s2[0].matches("[0-9]+")) //$NON-NLS-1$

+                            {

+                                boolean enableDump = !s2[1].contains(execPath);

+                                if (s2[1].contains("JCmd -l")) //$NON-NLS-1$

+                                    enableDump = false;

+                                IBMExecVmInfo ifo = new IBMExecVmInfo(s2[0], s2[1], enableDump, null, this);

+                                ifo.javaexecutable = javaExec;

+                                ifo.vmoptions = vmoptions;

+                                ar.add(ifo);

+                            }

+                        }

                     }

                 }

                 finally

diff --git a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMHeapDumpProvider.java b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMHeapDumpProvider.java
index ae711e7..ff9682f 100644
--- a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMHeapDumpProvider.java
+++ b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMHeapDumpProvider.java
@@ -1,10 +1,10 @@
 /*******************************************************************************

- * Copyright (c) 2010,2019 IBM Corporation

+ * Copyright (c) 2010,2021 IBM Corporation

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -113,13 +113,11 @@
 

         File result = mergeFileNames(preferredDump, dumps.get(0));

 

-        

         if (compress && !result.getName().endsWith(".gz")) //$NON-NLS-1$

         {

             result = new File(result.getPath()+".gz"); //$NON-NLS-1$

         }

-            

-        

+

         // See if dump names look as expected

         for (File dump : dumps)

         {

@@ -135,12 +133,16 @@
         final boolean zip = result.getName().endsWith(".gz"); //$NON-NLS-1$

         if (zip)

         {

+            File dump = dumps.get(0);

+            File dumpout = result.getCanonicalFile().equals(dump.getCanonicalFile()) ? 

+                            File.createTempFile(dump.getName(),  null, dump.getParentFile())

+                          : result;

             listener.subTask(Messages.getString("IBMDumpProvider.CompressingDump")); //$NON-NLS-1$

             int bufsize = 64 * 1024;

-            InputStream is = new BufferedInputStream(new FileInputStream(dumps.get(0)), bufsize);

+            InputStream is = new BufferedInputStream(new FileInputStream(dump), bufsize);

             try

             {

-                OutputStream os = new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream(result)));

+                OutputStream os = new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream(dumpout)));

                 try

                 {

                     byte buffer[] = new byte[bufsize];

@@ -169,6 +171,23 @@
             {

                 is.close();

             }

+            // No need to keep the uncompressed dump

+            if (dump.delete())

+            {

+                if (!dumpout.getCanonicalFile().equals(result.getCanonicalFile()) && !dumpout.renameTo(result))

+                {

+                    throw new IOException(result.getPath());

+                }

+            }

+            else

+            {

+                if (!dumpout.delete())

+                {

+                    throw new IOException(dumpout.getPath());

+                }

+                // Return uncompressed

+                result = dump;

+            }

         }

         int renamed = 0;

         for (int i = zip ? 1 : 0; i < dumps.size(); ++i)

@@ -204,11 +223,6 @@
                 return super.jextract(preferredDump, compress, dumps, udir, javahome, listener);

             }

         }

-        if (zip)

-        {

-            // No need to keep the uncompressed dump

-            dumps.get(0).delete();

-        }

         return result;

     }

-}
+}

diff --git a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMSystemDumpProvider.java b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMSystemDumpProvider.java
index 32e1498..762f26d 100644
--- a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMSystemDumpProvider.java
+++ b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMSystemDumpProvider.java
@@ -1,10 +1,10 @@
 /*******************************************************************************

- * Copyright (c) 2010, 2015 IBM Corporation

+ * Copyright (c) 2010, 2021 IBM Corporation

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -189,6 +189,12 @@
             if (!result.canRead()) { throw new FileNotFoundException(MessageFormat.format(Messages

                             .getString("IBMSystemDumpProvider.ReturnCode"), result.getPath(), errorBuf.toString())); //$NON-NLS-1$

             }

+

+            // Tidy up

+            if (!result.getCanonicalFile().equals(dump.getCanonicalPath()))

+            {

+                dump.delete();

+            }

         }

         else

         {

@@ -205,12 +211,6 @@
             result = dump;

         }

 

-        // Tidy up

-        if (zip)

-        {

-            dump.delete();

-        }

-

         listener.done();

 

         return result;

diff --git a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMVmInfo.java b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMVmInfo.java
index 31766ba..1e8a4ff 100644
--- a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMVmInfo.java
+++ b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMVmInfo.java
@@ -1,10 +1,10 @@
 /*******************************************************************************

- * Copyright (c) 2010, 2019 IBM Corporation

+ * Copyright (c) 2010, 2021 IBM Corporation

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -36,7 +36,7 @@
     @Argument(isMandatory = false)

     public boolean live = false;

 

-    @Argument

+    @Argument(isMandatory = false)

     public boolean compress = false;

 

     @Argument(isMandatory = false, advice = Advice.DIRECTORY)

diff --git a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/annotations.properties b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/annotations.properties
index c913cf4..e0feeb1 100644
--- a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/annotations.properties
+++ b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/annotations.properties
@@ -1,76 +1,81 @@
-###############################################################################
-# Copyright (c) 2010, 2021 IBM Corporation.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Eclipse Public License 2.0
-# which accompanies this distribution, and is available at
-# https://www.eclipse.org/legal/epl-2.0/
-#
-# SPDX-License-Identifier: EPL-2.0
-#
-# Contributors:
-#    IBM Corporation - initial implementation
-#    IBM Corporation/Andrew Johnson - Hprof additions
-###############################################################################
-BaseProvider.defaultType.help = Choose SYSTEM for a full system dump, optionally processed with jextract, \
-with full object, class, field name data and full field and array values. \n\
-Choose HEAP for a Portable Heap Dump, with object and class sizes and references, \
-but without field names, or primitive field and array values.\n\
-Choose JAVA for a Javadump, with only classes, class loaders and thread stacks \
-but without object or class sizes or references, \
-field names, or primitive field and array values.\n\
-Choose HPROF for a full dump from Oracle-based JVMs, \
-with full object, class, field name data and full field and array values.
-BaseProvider.defaultLive.help = Whether to dump live objects only. Selecting this may force a garbage collection on the target process before the dump.
-BaseProvider.defaultCompress.help = Whether to compress the generated dump, to save disk space at the possible cost of a longer load time.
-BaseProvider.listAttach.help = Whether to attach to every running JVM to get more details when listing all JVMs. This takes longer and may affect the JVM.
-BaseProvider.systemDumpTemplate.help = A template for the suggested system dump file name.
-BaseProvider.systemDumpZipTemplate.help = A template for the suggested compressed system dump file name.
-BaseProvider.heapDumpTemplate.help = A template for the suggested heap dump file name.
-BaseProvider.heapDumpZipTemplate.help = A template for the suggested compressed heap dump file name.
-BaseProvider.javaDumpTemplate.help = A template for the suggested Java dump file name.
-BaseProvider.hprofDumpTemplate.help = A template for the suggested HPROF dump file name.
-IBMExecDumpProvider.name = Attach API using a helper JVM
-IBMExecDumpProvider.help = This generates a dump from an IBM JVM, using a helper IBM JVM \
-with the Attach API to list the IBM JVMs and to attach to the target.\n\
-Also works for generating dumps from Oracle-based JVMs using a helper Oracle-based JDK JVM.
-IBMExecDumpProvider.javaexecutable.help = Path to an IBM 'java' executable, to provide the Attach API \
-to list and dump the target IBM JVMs.\n\
-Also can be a path to an Oracle-based JDK 'java' executable, to provide the Attach API \
-to list and dump the Oracle-based target JVMs.
-IBMExecDumpProvider.javaList.help = Paths to possible 'java' executables. Not used \
-directly but can be copied and pasted into the 'javaexecutable' field. \
-Clear the list to refresh.
-IBMExecDumpProvider.vmoptions.help = Options with which to run the helper JVM.
-IBMDumpProvider.name = Attach API
-IBMDumpProvider.help = This generates a dump from an IBM JVM, using the Attach API \
-supplied with the IBM JVM used to run Memory Analyzer \
-to list the IBM JVMs and to attach to the target.\n\
-Also works when MAT is run with an Oracle-based JDK JVM for generating dumps from Oracle-based VMs.
-IBMVmInfo.name = Configuration for a dump using the Attach API
-IBMVmInfo.help = This generates a dump from an IBM JVM using the Attach API.\n\
-Also works when MAT is run with an Oracle-based JDK JVM for generating dumps from Oracle-based JVMs.
-IBMVmInfo.type.help = Choose SYSTEM for a full system dump, optionally processed with jextract, \
-with full object, class, field name data and full field and array values. \n\
-Choose HEAP for a Portable Heap Dump, with object and class sizes and references, \
-but without field names, or primitive field and array values.\n\
-Choose JAVA for a Javadump, with only classes, class loaders and thread stacks \
-but without object or class sizes or references, \
-field names, or primitive field and array values.\n\
-Choose HPROF for a full dump from Oracle-based VMs, \
-with full object, class, field name data and full field and array values.
-IBMVmInfo.live.help = Whether to dump live objects only. Selecting this may force a garbage collection on the target process before the dump.
-IBMVmInfo.compress.help = Whether to compress the generated dump with jextract or gzip, to save disk space at the possible cost of a longer load time.
-IBMVmInfo.dumpdir.help = Alternative location used to find where the target JVM generates dump files. \
-If not specified then the system property 'user.dir' on the target JVM is used to find the dump files. This option \
-can be useful when JVM options have been used to select an alternative dump location or \
-on the Windows 7 operating system when writes to the program directory %ProgramFiles(x86)% \
-have been redirected to %LOCALAPPDATA%\\VirtualStore or %USERPROFILE%\\AppData\\Local\\VirtualStore.
-IBMExecVmInfo.name = Configuration for a dump using a helper JVM with the Attach API
-IBMExecVmInfo.help = This generates a dump from an IBM JVM, using a helper IBM JVM \
-to attach to the target IBM VM.\n\
-Also works with a helper Oracle-based JDK JVM for generating dumps from Oracle-based VMs.
-IBMExecVmInfo.javaexecutable.help = Path to an IBM 'java' executable, \
-to provide the Attach API to attach to the target IBM JVM.\n\
-Also can be a path to an Oracle-based JDK 'java' executable to provide the Attach API \
-to list and dump the Oracle-based target JVMs.
-IBMExecVmInfo.vmoptions.help = Options with which to run the helper JVM.
+###############################################################################

+# Copyright (c) 2010, 2021 IBM Corporation.

+# All rights reserved. This program and the accompanying materials

+# are made available under the terms of the Eclipse Public License 2.0

+# which accompanies this distribution, and is available at

+# https://www.eclipse.org/legal/epl-2.0/

+#

+# SPDX-License-Identifier: EPL-2.0

+#

+# Contributors:

+#    IBM Corporation - initial implementation

+#    IBM Corporation/Andrew Johnson - Hprof additions

+###############################################################################

+BaseProvider.defaultType.help = Choose SYSTEM for a full system dump, optionally processed with jextract, \

+with full object, class, field name data and full field and array values. \n\

+Choose HEAP for a Portable Heap Dump, with object and class sizes and references, \

+but without field names, or primitive field and array values.\n\

+Choose JAVA for a Javadump, with only classes, class loaders and thread stacks \

+but without object or class sizes or references, \

+field names, or primitive field and array values.\n\

+Choose HPROF for a full dump from OpenJDK or Oracle-based JVMs, \

+with full object, class, field name data and full field and array values.

+BaseProvider.defaultLive.help = Whether to dump live objects only. Selecting this may force a garbage collection on the target process before the dump.\n\

+Required when using some versions of jcmd.

+BaseProvider.defaultCompress.help = Whether to compress the generated dump, to save disk space at the possible cost of a longer load time.

+BaseProvider.listAttach.help = Whether to attach to every running JVM to get more details when listing all JVMs. This takes longer and may affect the JVM.

+BaseProvider.systemDumpTemplate.help = A template for the suggested system dump file name.

+BaseProvider.systemDumpZipTemplate.help = A template for the suggested compressed system dump file name.

+BaseProvider.heapDumpTemplate.help = A template for the suggested heap dump file name.

+BaseProvider.heapDumpZipTemplate.help = A template for the suggested compressed heap dump file name.

+BaseProvider.javaDumpTemplate.help = A template for the suggested Java dump file name.

+BaseProvider.hprofDumpTemplate.help = A template for the suggested HPROF dump file name.

+IBMExecDumpProvider.name = Attach API using a helper JVM

+IBMExecDumpProvider.help = This generates a dump from an OpenJ9 or IBM JVM, using a helper OpenJ9 or IBM JVM \

+with the Attach API to list the OpenJ9 or IBM JVMs and to attach to the target.\n\

+Also works for generating dumps from or OpenJDK or Oracle-based JVMs using a helper OpenJDK or Oracle-based JDK JVM. \

+Also works with the 'jcmd' utility.

+IBMExecDumpProvider.javaexecutable.help = Path to an OpenJ9 or IBM 'java' executable, to provide the Attach API \

+to list and dump the target OpenJ9 or IBM JVMs.\n\

+Also can be a path to an OpenJDK or Oracle-based JDK 'java' executable, to provide the Attach API \

+to list and dump the OpenJDK or Oracle-based target JVMs.\n\

+Also can be a path to a 'jcmd' executable, to list and dump the target JVMs.

+IBMExecDumpProvider.javaList.help = Paths to possible 'java' executables. Not used \

+directly but can be copied and pasted into the 'javaexecutable' field. \

+Clear the list to refresh.

+IBMExecDumpProvider.vmoptions.help = Options with which to run the helper JVM.

+IBMDumpProvider.name = Attach API

+IBMDumpProvider.help = This generates a dump from an OpenJ9 or IBM JVM, using the Attach API \

+supplied with the OpenJ9 or IBM JVM used to run Memory Analyzer \

+to list the OpenJ9 or IBM JVMs and to attach to the target.\n\

+Also works when MAT is run with an OpenJDK or Oracle-based JDK JVM for generating dumps from OpenJDK or Oracle-based JVMs.

+IBMVmInfo.name = Configuration for a dump using the Attach API

+IBMVmInfo.help = This generates a dump from an OpenJ9 or IBM JVM using the Attach API.\n\

+Also works when MAT is run with an OpenJDK or Oracle-based JDK JVM for generating dumps from OpenJDK or Oracle-based JVMs.

+IBMVmInfo.type.help = Choose SYSTEM for a full system dump, optionally processed with jextract, \

+with full object, class, field name data and full field and array values. \n\

+Choose HEAP for a Portable Heap Dump, with object and class sizes and references, \

+but without field names, or primitive field and array values.\n\

+Choose JAVA for a Javadump, with only classes, class loaders and thread stacks \

+but without object or class sizes or references, \

+field names, or primitive field and array values.\n\

+Choose HPROF for a full dump from OpenJDK or Oracle-based JVMs, \

+with full object, class, field name data and full field and array values.

+IBMVmInfo.live.help = Whether to dump live objects only. Selecting this may force a garbage collection on the target process before the dump.\n\

+Required when using some versions of jcmd.

+IBMVmInfo.compress.help = Whether to compress the generated dump with jextract or gzip, to save disk space at the possible cost of a longer load time.

+IBMVmInfo.dumpdir.help = Alternative location used to find where the target JVM generates dump files. \

+If not specified then the system property 'user.dir' on the target JVM is used to find the dump files.\n\

+This option can be useful when JVM options have been used to select an alternative dump location or \

+on the Windows 7 operating system when writes to the program directory %ProgramFiles(x86)% \

+have been redirected to %LOCALAPPDATA%\\VirtualStore or %USERPROFILE%\\AppData\\Local\\VirtualStore.

+IBMExecVmInfo.name = Configuration for a dump using a helper JVM with the Attach API

+IBMExecVmInfo.help = This generates a dump from an OpenJ9 or IBM JVM, using a helper OpenJ9 or IBM JVM \

+to attach to the target OpenJ9 or IBM JVM.\n\

+Also works with a helper OpenJDK or Oracle-based JDK JVM for generating dumps from OpenJDK or Oracle-based JVMs.

+IBMExecVmInfo.javaexecutable.help = Path to an OpenJ9 or IBM 'java' executable, \

+to provide the Attach API to attach to the target OpenJ9 or IBM JVM.\n\

+Also can be a path to an OpenJDK or Oracle-based JDK 'java' executable to provide the Attach API \

+to dump the OpenJDK or Oracle-based target JVMs.\n\

+Also can be a path to a 'jcmd' executable, to dump the target JVMs.

+IBMExecVmInfo.vmoptions.help = Options with which to run the helper JVM.

diff --git a/plugins/org.eclipse.mat.parser/doc/org_eclipse_mat_parser_parser.html b/plugins/org.eclipse.mat.parser/doc/org_eclipse_mat_parser_parser.html
index 74e336b..fd03abf 100644
--- a/plugins/org.eclipse.mat.parser/doc/org_eclipse_mat_parser_parser.html
+++ b/plugins/org.eclipse.mat.parser/doc/org_eclipse_mat_parser_parser.html
@@ -12,20 +12,26 @@
 <h6 class="CaptionFigColumn SchemaHeader">Since: </h6>0.7.0

 <p></p>

 

-<h6 class="CaptionFigColumn SchemaHeader">Description: </h6>The format of heap dumps is specific to the Virtual Machine used.
-This extensions allows to plug in new dump formats. Out of the box, the Memory Analyzer 
+<h6 class="CaptionFigColumn SchemaHeader">Description: </h6>The format of heap dumps is specific to the Virtual Machine used.

+This extensions allows to plug in new dump formats. Out of the box, the Memory Analyzer 

 supports HPROF and IBM dumps read via DTFJ. A DTFJ implementation is available from IBM developerWorks.<p></p>

 <h6 class="CaptionFigColumn SchemaHeader">Configuration Markup:</h6>

 <p></p>

 <p class="code SchemaDtd">&lt;!ELEMENT <a name="e.extension">extension</a> (<a href="#e.parser">parser</a>)&gt;</p>

 <p class="code SchemaDtd">&lt;!ATTLIST extension</p>

-<p class="code SchemaDtdAttlist">point&nbsp;CDATA #REQUIRED</p><p class="code SchemaDtdAttlist">id&nbsp;&nbsp;&nbsp;&nbsp;CDATA #REQUIRED</p><p class="code SchemaDtdAttlist">name&nbsp;&nbsp;CDATA #REQUIRED</p>&gt;</p>

+<p class="code SchemaDtdAttlist">point&nbsp;CDATA #REQUIRED</p>

+<p class="code SchemaDtdAttlist">id&nbsp;&nbsp;&nbsp;&nbsp;CDATA #REQUIRED</p>

+<p class="code SchemaDtdAttlist">name&nbsp;&nbsp;CDATA #REQUIRED&gt;</p>

 <p></p>

 <ul class="ConfigMarkupAttlistDesc">

 </ul>

-<br><p class="code SchemaDtd">&lt;!ELEMENT <a name="e.parser">parser</a> EMPTY&gt;</p>

+<br><p class="code SchemaDtd">&lt;!ELEMENT <a name="e.parser">parser</a> (<a href="#e.contentTypeBinding">contentTypeBinding</a>*)&gt;</p>

 <p class="code SchemaDtd">&lt;!ATTLIST parser</p>

-<p class="code SchemaDtdAttlist">name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDATA #REQUIRED</p><p class="code SchemaDtdAttlist">fileExtension&nbsp;CDATA #REQUIRED</p><p class="code SchemaDtdAttlist">indexBuilder&nbsp;&nbsp;CDATA #REQUIRED</p><p class="code SchemaDtdAttlist">objectReader&nbsp;&nbsp;CDATA #REQUIRED</p><p class="code SchemaDtdAttlist">dynamic&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDATA #IMPLIED</p>&gt;</p>

+<p class="code SchemaDtdAttlist">name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDATA #REQUIRED</p>

+<p class="code SchemaDtdAttlist">fileExtension&nbsp;CDATA #REQUIRED</p>

+<p class="code SchemaDtdAttlist">indexBuilder&nbsp;&nbsp;CDATA #REQUIRED</p>

+<p class="code SchemaDtdAttlist">objectReader&nbsp;&nbsp;CDATA #REQUIRED</p>

+<p class="code SchemaDtdAttlist">dynamic&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDATA #IMPLIED&gt;</p>

 <p></p>

 <ul class="ConfigMarkupAttlistDesc">

 <li><b>name</b> - Name of the heap dump format. For example, shown in the file selection dialog.</li>

@@ -34,57 +40,67 @@
 <li><b>objectReader</b> - implementor of <a href="org/eclipse/mat/parser/IObjectReader.html"><samp>org.eclipse.mat.parser.IObjectReader</samp></a> to read the object details from the heap dump file</li>

 <li><b>dynamic</b> - This is a class which extends java.util.Map and returns a set of extensions and descriptions, together with ids which replace the attributes "id", "name", "fileExtension" in the dynamic parser.</li>

 </ul>

-<br><h6 class="CaptionFigColumn SchemaHeader">Examples: </h6>Following is an example of a parser declaration: 
-<p>
-<pre class="Example"><span class="code SchemaTag">
-   &lt;extension
-         id=</span><span class="code SchemaCstring">&quot;hprof&quot;</span><span class="code SchemaTag">
-         name=</span><span class="code SchemaCstring">&quot;HPROF Formatted Dumps&quot;</span><span class="code SchemaTag">
-         point=</span><span class="code SchemaCstring">&quot;org.eclipse.mat.parser.parser&quot;</span><span class="code SchemaTag">&gt;
-      &lt;parser
-        name=</span><span class="code SchemaCstring">&quot;HPROF binary heap dumps&quot;</span><span class="code SchemaTag">
-            fileExtension=</span><span class="code SchemaCstring">&quot;hprof,bin&quot;</span><span class="code SchemaTag">
-            indexBuilder=</span><span class="code SchemaCstring">&quot;org.eclipse.mat.hprof.HprofIndexBuilder&quot;</span><span class="code SchemaTag">
-            objectReader=</span><span class="code SchemaCstring">&quot;org.eclipse.mat.hprof.HprofHeapObjectReader&quot;</span><span class="code SchemaTag">&gt;
-      &lt;/parser&gt;
-   &lt;/extension&gt;
-</span></pre>
+<br><p class="code SchemaDtd">&lt;!ELEMENT <a name="e.contentTypeBinding">contentTypeBinding</a> EMPTY&gt;</p>

+<p class="code SchemaDtd">&lt;!ATTLIST contentTypeBinding</p>

+<p class="code SchemaDtdAttlist">contentTypeId&nbsp;IDREF #REQUIRED&gt;</p>

+<p></p>

+<p class="ConfigMarkupElementDesc">

+Advertises that the containing parser understands the given content type and is suitable for parsing files of that type.</p>

+<br>

+<ul class="ConfigMarkupAttlistDesc">

+<li><b>contentTypeId</b> - The content type identifier. This is an ID defined by the 'org.eclipse.core.contenttype.contentTypes' extension point.</li>

+</ul>

+<br><h6 class="CaptionFigColumn SchemaHeader">Examples: </h6>Following is an example of a parser declaration: 

+<p>

+<pre class="Example"><span class="code SchemaTag">

+   &lt;extension

+         id=</span><span class="code SchemaCstring">&quot;hprof&quot;</span><span class="code SchemaTag">

+         name=</span><span class="code SchemaCstring">&quot;HPROF Formatted Dumps&quot;</span><span class="code SchemaTag">

+         point=</span><span class="code SchemaCstring">&quot;org.eclipse.mat.parser.parser&quot;</span><span class="code SchemaTag">&gt;

+      &lt;parser

+        name=</span><span class="code SchemaCstring">&quot;HPROF binary heap dumps&quot;</span><span class="code SchemaTag">

+            fileExtension=</span><span class="code SchemaCstring">&quot;hprof,bin&quot;</span><span class="code SchemaTag">

+            indexBuilder=</span><span class="code SchemaCstring">&quot;org.eclipse.mat.hprof.HprofIndexBuilder&quot;</span><span class="code SchemaTag">

+            objectReader=</span><span class="code SchemaCstring">&quot;org.eclipse.mat.hprof.HprofHeapObjectReader&quot;</span><span class="code SchemaTag">&gt;

+      &lt;/parser&gt;

+   &lt;/extension&gt;

+</span></pre>

 </p>

 <p></p>

 

-<h6 class="CaptionFigColumn SchemaHeader">API Information: </h6>The value of the indexBuilder attribute must represent an implementor of <samp>org.eclipse.mat.parser.IIndexBuilder</samp>,
-the objectReader attribute <samp>org.eclipse.mat.parser.IObjectReader</samp>.
-
-The dynamicParser attribute is a class which extends java.util.Map and returns a set of extensions and descriptions, together with ids which replace the attributes "id", "name", "fileExtension" in the dynamic parser.
-<pre class="Example"><span class="code SchemaTag">
-Map&lt;String, Map&lt;String, String&gt;&gt;
-</span></pre>
-
-<dl>
-<dt>Main id</dt>
-<dd>fully qualified id for each parser
-<dl>
-  <dt>id</dt><dd>fully qualified id for the parser</dd>
-  <dt>name</dt><dd>readable name for the parser</dd>
-  <dt>fileExtension</dt><dd>file extensions for this parser</dd>
-</dl>
-</dd>
-</dl>
-  
-The subparsers share the indexBuilder and objectReader.
+<h6 class="CaptionFigColumn SchemaHeader">API Information: </h6>The value of the indexBuilder attribute must represent an implementor of <samp>org.eclipse.mat.parser.IIndexBuilder</samp>,

+the objectReader attribute <samp>org.eclipse.mat.parser.IObjectReader</samp>.

+

+The dynamicParser attribute is a class which extends java.util.Map and returns a set of extensions and descriptions, together with ids which replace the attributes "id", "name", "fileExtension" in the dynamic parser.

+<pre class="Example"><span class="code SchemaTag">

+Map&lt;String, Map&lt;String, String&gt;&gt;

+</span></pre>

+

+<dl>

+<dt>Main id</dt>

+<dd>fully qualified id for each parser

+<dl>

+  <dt>id</dt><dd>fully qualified id for the parser</dd>

+  <dt>name</dt><dd>readable name for the parser</dd>

+  <dt>fileExtension</dt><dd>file extensions for this parser</dd>

+</dl>

+</dd>

+</dl>

+  

+The subparsers share the indexBuilder and objectReader.

 <p>This is used for example by the DTFJ parser which has to find out at run time which DTFJ implementations are available and to create an MAT parser definition for each one.</p>

 <p></p>

 

-<h6 class="CaptionFigColumn SchemaHeader">Supplied Implementation: </h6>The Memory Analyzer supplies an implementation for HPROF and IBM DTFJ format dumps. Check out the <samp>org.eclipse.mat.hprof</samp> plug-in and <samp>org.eclipse.mat.dtfj</samp> plug-in.
+<h6 class="CaptionFigColumn SchemaHeader">Supplied Implementation: </h6>The Memory Analyzer supplies an implementation for HPROF and IBM DTFJ format dumps. Check out the <samp>org.eclipse.mat.hprof</samp> plug-in and <samp>org.eclipse.mat.dtfj</samp> plug-in.

  A DTFJ implementation is available from IBM DeveloperWorks.

 <p></p>

 

 <br>

 <p class="note SchemaCopyright">

-Copyright (c) 2008,2011 SAP AG and IBM Corporation.<br>
-All rights reserved. This program and the accompanying materials are made 
-available under the terms of the Eclipse Public License 2.0 which 
-accompanies this distribution, and is available at 
+Copyright (c) 2008,2021 SAP AG and IBM Corporation.<br>

+All rights reserved. This program and the accompanying materials are made 

+available under the terms of the Eclipse Public License 2.0 which 

+accompanies this distribution, and is available at 

 <a href="https://www.eclipse.org/legal/epl-2.0/">https://www.eclipse.org/legal/epl-2.0/</a>

 

 </p>

diff --git a/plugins/org.eclipse.mat.parser/schema/parser.exsd b/plugins/org.eclipse.mat.parser/schema/parser.exsd
index 2565c80..569a85e 100644
--- a/plugins/org.eclipse.mat.parser/schema/parser.exsd
+++ b/plugins/org.eclipse.mat.parser/schema/parser.exsd
@@ -51,6 +51,9 @@
 

    <element name="parser">

       <complexType>

+         <sequence>

+            <element ref="contentTypeBinding" minOccurs="0" maxOccurs="unbounded"/>

+         </sequence>

          <attribute name="name" type="string" use="required">

             <annotation>

                <documentation>

@@ -101,6 +104,29 @@
       </complexType>

    </element>

 

+   <element name="contentTypeBinding">

+      <annotation>

+         <appInfo>

+            <meta.element labelAttribute="contentTypeId"/>

+         </appInfo>

+         <documentation>

+            Advertises that the containing parser understands the given content type and is suitable for parsing files of that type.

+         </documentation>

+      </annotation>

+      <complexType>

+         <attribute name="contentTypeId" type="string" use="required">

+            <annotation>

+               <documentation>

+                  The content type identifier. This is an ID defined by the &apos;org.eclipse.core.contenttype.contentTypes&apos; extension point.

+               </documentation>

+               <appInfo>

+                  <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/>

+               </appInfo>

+            </annotation>

+         </attribute>

+      </complexType>

+   </element>

+

    <annotation>

       <appInfo>

          <meta.section type="since"/>

@@ -136,29 +162,6 @@
 

    <annotation>

       <appInfo>

-         <meta.section type="implementation"/>

-      </appInfo>

-      <documentation>

-         The Memory Analyzer supplies an implementation for HPROF and IBM DTFJ format dumps. Check out the &lt;samp&gt;org.eclipse.mat.hprof&lt;/samp&gt; plug-in and &lt;samp&gt;org.eclipse.mat.dtfj&lt;/samp&gt; plug-in.

- A DTFJ implementation is available from IBM DeveloperWorks.

-      </documentation>

-   </annotation>

-

-   <annotation>

-      <appInfo>

-         <meta.section type="copyright"/>

-      </appInfo>

-      <documentation>

-         Copyright (c) 2008,2011 SAP AG and IBM Corporation.&lt;br&gt;

-All rights reserved. This program and the accompanying materials are made 

-available under the terms of the Eclipse Public License 2.0 which 

-accompanies this distribution, and is available at 

-&lt;a href=&quot;https://www.eclipse.org/legal/epl-2.0/&quot;&gt;https://www.eclipse.org/legal/epl-2.0/&lt;/a&gt;

-      </documentation>

-   </annotation>

-

-   <annotation>

-      <appInfo>

          <meta.section type="apiInfo"/>

       </appInfo>

       <documentation>

@@ -186,4 +189,27 @@
       </documentation>

    </annotation>

 

+   <annotation>

+      <appInfo>

+         <meta.section type="implementation"/>

+      </appInfo>

+      <documentation>

+         The Memory Analyzer supplies an implementation for HPROF and IBM DTFJ format dumps. Check out the &lt;samp&gt;org.eclipse.mat.hprof&lt;/samp&gt; plug-in and &lt;samp&gt;org.eclipse.mat.dtfj&lt;/samp&gt; plug-in.

+ A DTFJ implementation is available from IBM DeveloperWorks.

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appInfo>

+         <meta.section type="copyright"/>

+      </appInfo>

+      <documentation>

+         Copyright (c) 2008,2021 SAP AG and IBM Corporation.&lt;br&gt;

+All rights reserved. This program and the accompanying materials are made 

+available under the terms of the Eclipse Public License 2.0 which 

+accompanies this distribution, and is available at 

+&lt;a href=&quot;https://www.eclipse.org/legal/epl-2.0/&quot;&gt;https://www.eclipse.org/legal/epl-2.0/&lt;/a&gt;

+      </documentation>

+   </annotation>

+

 </schema>

diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/SnapshotFactoryImpl.java b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/SnapshotFactoryImpl.java
index 12fd533..24944fb 100644
--- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/SnapshotFactoryImpl.java
+++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/SnapshotFactoryImpl.java
@@ -1,10 +1,10 @@
 /*******************************************************************************

- * Copyright (c) 2008, 2020 SAP AG and IBM Corporation.

+ * Copyright (c) 2008, 2021 SAP AG and IBM Corporation.

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -13,10 +13,12 @@
  *******************************************************************************/

 package org.eclipse.mat.parser.internal;

 

+import java.io.ByteArrayInputStream;

 import java.io.File;

 import java.io.FileFilter;

 import java.io.FileInputStream;

 import java.io.IOException;

+import java.io.InputStream;

 import java.lang.ref.WeakReference;

 import java.util.ArrayList;

 import java.util.Date;

@@ -32,6 +34,7 @@
 import org.eclipse.core.runtime.MultiStatus;

 import org.eclipse.core.runtime.Platform;

 import org.eclipse.core.runtime.Status;

+import org.eclipse.core.runtime.content.IContentDescription;

 import org.eclipse.core.runtime.content.IContentType;

 import org.eclipse.core.runtime.content.IContentTypeManager;

 import org.eclipse.mat.SnapshotException;

@@ -94,6 +97,7 @@
          */

         IContentTypeManager contentTypeManager = Platform.getContentTypeManager();

         IContentType javaheapdump = contentTypeManager.getContentType("org.eclipse.mat.JavaHeapDump"); //$NON-NLS-1$

+        List<IContentType>listtypes = new ArrayList<IContentType>();

         if (javaheapdump != null)

         {

             String n1 = name;

@@ -101,6 +105,13 @@
             try (FileInputStream fis = new FileInputStream(file))

             {

                 types = contentTypeManager.findContentTypesFor(fis, file.getPath());

+                if (types.length == 0)

+                {

+                    try (FileInputStream fis2 = new FileInputStream(file))

+                    {

+                        types = contentTypeManager.findContentTypesFor(fis2, null);

+                    }

+                }

             }

             catch (IOException e)

             {

@@ -111,6 +122,28 @@
             {

                 if (tp.isKindOf(javaheapdump))

                 {

+                    // See if this content description is based on the file contents

+                    IContentDescription cd1, cd2;

+                    try (FileInputStream fis = new FileInputStream(file))

+                    {

+                        // Succeeds if based on context

+                        cd1 = tp.getDescriptionFor(fis, IContentDescription.ALL);

+                    }

+                    catch (IOException e)

+                    {

+                        cd1 = null;

+                    }

+                    try (InputStream sr = new ByteArrayInputStream(new byte[10]))

+                    {

+                        // Succeeds if generic type without content checking

+                        cd2 = tp.getDescriptionFor(sr, IContentDescription.ALL);

+                    }

+                    catch (IOException e)

+                    {

+                        cd2 = null;

+                    }

+                    if (cd1 != null && cd2 == null)

+                        listtypes.add(tp);

                     for (String ext: tp.getFileSpecs(IContentType.FILE_EXTENSION_SPEC))

                     {

                         // Does extension itself contains a dot, and matches this file ?

@@ -166,7 +199,7 @@
         if (answer == null)

         {

             deleteIndexFiles(file, prefix, listener);

-            answer = parse(file, prefix, args, listener);

+            answer = parse(file, prefix, args, listtypes, listener);

         }

 

         entry = new SnapshotEntry(1, answer);

@@ -224,13 +257,36 @@
     // Internal implementations

     // //////////////////////////////////////////////////////////////

 

-    private final ISnapshot parse(File file, String prefix, Map<String, String> args, IProgressListener listener) throws SnapshotException

+    private final ISnapshot parse(File file, String prefix, Map<String, String> args, List<IContentType>listtypes, IProgressListener listener) throws SnapshotException

     {

         ParserRegistry registry = ParserPlugin.getDefault().getParserRegistry();

 

         List<ParserRegistry.Parser> parsers = registry.matchParser(file.getName());

         if (parsers.isEmpty())

             parsers.addAll(registry.delegates()); // try all...

+        else

+        {

+            // Add some extra parsers by content type

+            for (IContentType type : listtypes)

+            {

+                // Parsers don't match for equality

+                List<ParserRegistry.Parser> parsers2 = registry.matchParser(type);

+                for (ParserRegistry.Parser p2 : parsers2)

+                {

+                    boolean found = false;

+                    for (ParserRegistry.Parser p3 : parsers)

+                    {

+                        if (p3.getId().equals(p2.getId()))

+                        {

+                            found = true;

+                            break;

+                        }

+                    }

+                    if (!found)

+                        parsers.add(p2);

+                }

+            }

+        }

 

         List<IOException> errors = new ArrayList<IOException>();

 

diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/util/ParserRegistry.java b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/util/ParserRegistry.java
index 886adf0..ed2879d 100644
--- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/util/ParserRegistry.java
+++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/util/ParserRegistry.java
@@ -1,14 +1,15 @@
 /*******************************************************************************

- * Copyright (c) 2008, 2010 SAP AG and others.

+ * Copyright (c) 2008, 2021 SAP AG, IBM Corporation and others.

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

  *    SAP AG - initial API and implementation

+ *    Andrew Johnson - content types

  *******************************************************************************/

 package org.eclipse.mat.parser.internal.util;

 

@@ -26,6 +27,7 @@
 import org.eclipse.core.runtime.CoreException;

 import org.eclipse.core.runtime.IConfigurationElement;

 import org.eclipse.core.runtime.IExtension;

+import org.eclipse.core.runtime.content.IContentType;

 import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;

 import org.eclipse.mat.parser.internal.Messages;

 import org.eclipse.mat.parser.internal.ParserPlugin;

@@ -42,6 +44,8 @@
     private static final String DYNAMIC = "dynamic";//$NON-NLS-1$

     public static final String INDEX_BUILDER = "indexBuilder";//$NON-NLS-1$

     public static final String OBJECT_READER = "objectReader";//$NON-NLS-1$

+    public static final String CONTENT_TYPE_BINDING = "contentTypeBinding";//$NON-NLS-1$

+    public static final String CONTENT_TYPE_ID = "contentTypeId";//$NON-NLS-1$

 

     public class Parser

     {

@@ -49,6 +53,16 @@
         private IConfigurationElement configElement;

         private SnapshotFormat snapshotFormat;

         private Pattern[] pattern;

+        private String[] contentTypes;

+

+        private Parser(IConfigurationElement configElement, String id, SnapshotFormat snapshotFormat, Pattern[] pattern, String contentTypes[])

+        {

+            this.id = id;

+            this.configElement = configElement;

+            this.snapshotFormat = snapshotFormat;

+            this.pattern = pattern;

+            this.contentTypes = contentTypes;

+        }

 

         private Parser(IConfigurationElement configElement, String id, SnapshotFormat snapshotFormat, Pattern[] pattern)

         {

@@ -56,6 +70,12 @@
             this.configElement = configElement;

             this.snapshotFormat = snapshotFormat;

             this.pattern = pattern;

+            IConfigurationElement bindings[] = configElement.getChildren(CONTENT_TYPE_BINDING);

+            contentTypes = new String[bindings.length];

+            for (int i = 0; i < bindings.length; ++i)

+            {

+                contentTypes[i] = bindings[i].getAttribute(CONTENT_TYPE_ID);

+            }

         }

 

         private Parser(IConfigurationElement configElement, SnapshotFormat snapshotFormat, Pattern[] pattern)

@@ -175,7 +195,27 @@
         }

         return answer;

     }

-    

+

+    public List<Parser> matchParser(IContentType contentType)

+    {

+        List<Parser> answer = new ArrayList<Parser>();

+        for (Parser p : delegates())

+        {

+            loop:for (IContentType tp = contentType; tp != null; tp = tp.getBaseType())

+            {

+                for (String type : p.contentTypes)

+                {

+                    if (tp.getId().equals(type))

+                    {

+                        answer.add(p);

+                        break loop;

+                    }

+                }

+            }

+        }

+        return answer;

+    }

+

     @Override

     public Collection<Parser> delegates()

     {

@@ -210,7 +250,16 @@
                                     patterns[ii] = Pattern.compile("(.*\\.)((?i)" + extensions[ii] + ")(\\.[0-9]*)?");//$NON-NLS-1$//$NON-NLS-2$

 

                                 SnapshotFormat snapshotFormat = new SnapshotFormat(name, extensions);

-                                res2.add(new Parser(p.configElement, id, snapshotFormat, patterns));

+                                String contentType = m.get(CONTENT_TYPE_BINDING);

+                                if (contentType != null)

+                                {

+                                    String[] contentTypes = SimpleStringTokenizer.split(contentType, ',');

+                                    res2.add(new Parser(p.configElement, id, snapshotFormat, patterns, contentTypes));

+                                }

+                                else

+                                {

+                                    res2.add(new Parser(p.configElement, id, snapshotFormat, patterns));

+                                }

                             }

                             catch (PatternSyntaxException e)

                             {

diff --git a/plugins/org.eclipse.mat.report/META-INF/MANIFEST.MF b/plugins/org.eclipse.mat.report/META-INF/MANIFEST.MF
index 3ac0756..8ce3f50 100644
--- a/plugins/org.eclipse.mat.report/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.mat.report/META-INF/MANIFEST.MF
@@ -15,7 +15,6 @@
  org.eclipse.mat.query.registry;x-friends:="org.eclipse.mat.ui,org.eclipse.mat.api,org.eclipse.mat.chart,org.eclipse.mat.chart.ui",

  org.eclipse.mat.query.results,

  org.eclipse.mat.report,

- org.eclipse.mat.report.internal;x-friends:="org.eclipse.mat.ui",

  org.eclipse.mat.util

 Require-Bundle: org.eclipse.core.runtime;bundle-version="3.3.100"

 Eclipse-BuddyPolicy: dependent

diff --git a/plugins/org.eclipse.mat.report/doc/org_eclipse_mat_report_renderer.html b/plugins/org.eclipse.mat.report/doc/org_eclipse_mat_report_renderer.html
index b689d51..4ac0109 100644
--- a/plugins/org.eclipse.mat.report/doc/org_eclipse_mat_report_renderer.html
+++ b/plugins/org.eclipse.mat.report/doc/org_eclipse_mat_report_renderer.html
@@ -12,68 +12,70 @@
 <h6 class="CaptionFigColumn SchemaHeader">Since: </h6>0.7.0

 <p></p>

 

-<h6 class="CaptionFigColumn SchemaHeader">Description: </h6>The Memory Analyzer report generator utilizes the renderer to create
-a textual representation of the query results, e.g. the table,
-trees, histograms, etc. Out of the box, HTML and CSV are supported.
+<h6 class="CaptionFigColumn SchemaHeader">Description: </h6>The Memory Analyzer report generator utilizes the renderer to create

+a textual representation of the query results, e.g. the table,

+trees, histograms, etc. Out of the box, HTML, CSV and TXT are supported.

 This is the extension point to add an alternative renderer.<p></p>

 <h6 class="CaptionFigColumn SchemaHeader">Configuration Markup:</h6>

 <p></p>

 <p class="code SchemaDtd">&lt;!ELEMENT <a name="e.extension">extension</a> (<a href="#e.renderer">renderer</a>)+&gt;</p>

 <p class="code SchemaDtd">&lt;!ATTLIST extension</p>

-<p class="code SchemaDtdAttlist">point&nbsp;CDATA #REQUIRED</p><p class="code SchemaDtdAttlist">id&nbsp;&nbsp;&nbsp;&nbsp;CDATA #IMPLIED</p><p class="code SchemaDtdAttlist">name&nbsp;&nbsp;CDATA #IMPLIED</p>&gt;</p>

+<p class="code SchemaDtdAttlist">point&nbsp;CDATA #REQUIRED</p>

+<p class="code SchemaDtdAttlist">id&nbsp;&nbsp;&nbsp;&nbsp;CDATA #IMPLIED</p>

+<p class="code SchemaDtdAttlist">name&nbsp;&nbsp;CDATA #IMPLIED&gt;</p>

 <p></p>

 <ul class="ConfigMarkupAttlistDesc">

 </ul>

 <br><p class="code SchemaDtd">&lt;!ELEMENT <a name="e.renderer">renderer</a> EMPTY&gt;</p>

 <p class="code SchemaDtd">&lt;!ATTLIST renderer</p>

-<p class="code SchemaDtdAttlist">impl&nbsp;CDATA #REQUIRED</p>&gt;</p>

+<p class="code SchemaDtdAttlist">impl&nbsp;CDATA #REQUIRED&gt;</p>

 <p></p>

 <ul class="ConfigMarkupAttlistDesc">

 <li><b>impl</b> - implementor of <a href="org/eclipse/mat/report/IOutputter.html"><samp>org.eclipse.mat.report.IOutputter</samp></a>.</li>

 </ul>

-<br><h6 class="CaptionFigColumn SchemaHeader">Examples: </h6>Following is an example of a renderer declaration: 
-<p>
-<pre class="Example"><span class="code SchemaTag">
-   &lt;extension point=</span><span class="code SchemaCstring">&quot;org.eclipse.mat.report.renderer&quot;</span><span class="code SchemaTag">&gt;
-      &lt;renderer impl=</span><span class="code SchemaCstring">&quot;org.eclipse.mat.report.internal.CsvRenderer&quot;</span><span class="code SchemaTag"> /&gt;
-   &lt;/extension&gt;
-</span></pre>
-</p>
-The renderer must implement <samp>org.eclipse.mat.report.IOutputter</samp>.
-The <samp>@Renderer</samp> annotation declares the target format and,
-optionally, the applicable result type.
-<p>
-<pre class="Example"><span class="code SchemaTag">
-@Renderer(target = "csv", result = IResult.class)
-public class CsvRenderer implements IOutputter
-{
-   [...]
-}
-</span></pre>
-</p>
-In the report, use the "format" parameter to specify the output format:
-<p>
-<pre class="Example"><span class="code SchemaTag">
-   &lt;query name=</span><span class="code SchemaCstring">&quot;Class Histogram&quot;</span><span class="code SchemaTag">&gt;
-      &lt;param key=</span><span class="code SchemaCstring">&quot;format&quot;</span><span class="code SchemaTag"> value=</span><span class="code SchemaCstring">&quot;csv&quot;</span><span class="code SchemaTag"> /&gt;
-      &lt;command&gt;histogram&lt;/command&gt;
-   &lt;/query&gt;
-</span></pre>
+<br><h6 class="CaptionFigColumn SchemaHeader">Examples: </h6>Following is an example of a renderer declaration: 

+<p>

+<pre class="Example"><span class="code SchemaTag">

+   &lt;extension point=</span><span class="code SchemaCstring">&quot;org.eclipse.mat.report.renderer&quot;</span><span class="code SchemaTag">&gt;

+      &lt;renderer impl=</span><span class="code SchemaCstring">&quot;org.eclipse.mat.report.internal.CsvRenderer&quot;</span><span class="code SchemaTag"> /&gt;

+   &lt;/extension&gt;

+</span></pre>

+</p>

+The renderer must implement <samp>org.eclipse.mat.report.IOutputter</samp>.

+The <samp>@Renderer</samp> annotation declares the target format and,

+optionally, the applicable result type.

+<p>

+<pre class="Example"><span class="code SchemaTag">

+@Renderer(target = "csv", result = IResult.class)

+public class CsvRenderer implements IOutputter

+{

+   [...]

+}

+</span></pre>

+</p>

+In the report, use the "format" parameter to specify the output format:

+<p>

+<pre class="Example"><span class="code SchemaTag">

+   &lt;query name=</span><span class="code SchemaCstring">&quot;Class Histogram&quot;</span><span class="code SchemaTag">&gt;

+      &lt;param key=</span><span class="code SchemaCstring">&quot;format&quot;</span><span class="code SchemaTag"> value=</span><span class="code SchemaCstring">&quot;csv&quot;</span><span class="code SchemaTag"> /&gt;

+      &lt;command&gt;histogram&lt;/command&gt;

+   &lt;/query&gt;

+</span></pre>

 </p>

 <p></p>

 

 <h6 class="CaptionFigColumn SchemaHeader">API Information: </h6>The value of the impl attribute must represent an implementor of <samp>org.eclipse.mat.report.IOutputter</samp>.

 <p></p>

 

-<h6 class="CaptionFigColumn SchemaHeader">Supplied Implementation: </h6>The Memory Analyzer supplies two renderers: one for HTML, one for CSV (comma separated values).

+<h6 class="CaptionFigColumn SchemaHeader">Supplied Implementation: </h6>The Memory Analyzer supplies three renderers: one for HTML, one for CSV (comma separated values) and one for TXT (plain text).

 <p></p>

 

 <br>

 <p class="note SchemaCopyright">

-Copyright (c) 2008 SAP AG and others.<br>
-All rights reserved. This program and the accompanying materials are made 
-available under the terms of the Eclipse Public License 2.0 which 
-accompanies this distribution, and is available at 
+Copyright (c) 2008,2021 SAP AG, IBM Corporation and others.<br>

+All rights reserved. This program and the accompanying materials are made 

+available under the terms of the Eclipse Public License 2.0 which 

+accompanies this distribution, and is available at 

 <a href="https://www.eclipse.org/legal/epl-2.0/">https://www.eclipse.org/legal/epl-2.0/</a>

 

 </p>

diff --git a/plugins/org.eclipse.mat.report/schema/renderer.exsd b/plugins/org.eclipse.mat.report/schema/renderer.exsd
index 0287b4e..4e15766 100644
--- a/plugins/org.eclipse.mat.report/schema/renderer.exsd
+++ b/plugins/org.eclipse.mat.report/schema/renderer.exsd
@@ -8,7 +8,7 @@
       <documentation>

          The Memory Analyzer report generator utilizes the renderer to create

 a textual representation of the query results, e.g. the table,

-trees, histograms, etc. Out of the box, HTML and CSV are supported.

+trees, histograms, etc. Out of the box, HTML, CSV and TXT are supported.

 This is the extension point to add an alternative renderer.

       </documentation>

    </annotation>

@@ -113,10 +113,19 @@
 

    <annotation>

       <appInfo>

+         <meta.section type="apiInfo"/>

+      </appInfo>

+      <documentation>

+         The value of the impl attribute must represent an implementor of &lt;samp&gt;org.eclipse.mat.report.IOutputter&lt;/samp&gt;.

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appInfo>

          <meta.section type="implementation"/>

       </appInfo>

       <documentation>

-         The Memory Analyzer supplies two renderers: one for HTML, one for CSV (comma separated values).

+         The Memory Analyzer supplies three renderers: one for HTML, one for CSV (comma separated values) and one for TXT (plain text).

       </documentation>

    </annotation>

 

@@ -125,7 +134,7 @@
          <meta.section type="copyright"/>

       </appInfo>

       <documentation>

-         Copyright (c) 2008 SAP AG and others.&lt;br&gt;

+         Copyright (c) 2008,2021 SAP AG, IBM Corporation and others.&lt;br&gt;

 All rights reserved. This program and the accompanying materials are made 

 available under the terms of the Eclipse Public License 2.0 which 

 accompanies this distribution, and is available at 

@@ -133,13 +142,4 @@
       </documentation>

    </annotation>

 

-   <annotation>

-      <appInfo>

-         <meta.section type="apiInfo"/>

-      </appInfo>

-      <documentation>

-         The value of the impl attribute must represent an implementor of &lt;samp&gt;org.eclipse.mat.report.IOutputter&lt;/samp&gt;.

-      </documentation>

-   </annotation>

-

 </schema>

diff --git a/plugins/org.eclipse.mat.report/schema/report.xsd b/plugins/org.eclipse.mat.report/schema/report.xsd
index 938e595..74db0d1 100644
--- a/plugins/org.eclipse.mat.report/schema/report.xsd
+++ b/plugins/org.eclipse.mat.report/schema/report.xsd
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-    Copyright (c) 2011, 2018 IBM Corporation.
+    Copyright (c) 2011, 2021 IBM Corporation.
     All rights reserved. This program and the accompanying materials
     are made available under the terms of the Eclipse Public License 2.0
     which accompanies this distribution, and is available at
@@ -122,6 +122,7 @@
 		<xs:restriction base="xs:string">
 			<xs:enumeration value="csv" />
 			<xs:enumeration value="html" />
+			<xs:enumeration value="txt" />
 		</xs:restriction>
 	</xs:simpleType>
 
diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextOutputter.java b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextOutputter.java
index e1df582..aaba55c 100644
--- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextOutputter.java
+++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextOutputter.java
@@ -428,6 +428,13 @@
         }

 

         @Override

+        protected String getDisplayableRowValue(Object item)

+        {

+            // Special work-around case for trees with no columns, e.g. navigation history returned by Copy

+            return tree.getColumnValue(item, -1).toString();

+        }

+

+        @Override

         protected String getItemValue(Object item, int columnIndex)

         {

             if (item instanceof Filter[])

diff --git a/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/acquire/AcquireDumpTest.java b/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/acquire/AcquireDumpTest.java
index 23fde5c..1cbc3b2 100644
--- a/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/acquire/AcquireDumpTest.java
+++ b/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/acquire/AcquireDumpTest.java
@@ -3,8 +3,8 @@
  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -63,8 +63,8 @@
     HeapDumpProviderDescriptor hdpd;

     int num;

     int nall;

-    static int count;

-    static int found;

+    private static int count;

+    private static int found;

     public AcquireDumpTest(HeapDumpProviderDescriptor hdpd, String name, int id, int n)

     {

         this.hdpd = hdpd;

@@ -121,7 +121,6 @@
      */

     public void test3(boolean compress, boolean chunked) throws SnapshotException, IOException

     {

-        Collection<HeapDumpProviderDescriptor> descs = HeapDumpProviderRegistry.instance().getHeapDumpProviders();

         File tmpdir = TestSnapshots.createGeneratedName("acquire", null);

         HeapDumpProviderDescriptor hd = hdpd;

         do {

@@ -145,7 +144,7 @@
                 continue;

             for (VmInfo vm : ls)

             {

-                ++count;

+                incCount();

                 String desc = vm.getDescription();

                 collector.checkThat("VM description", desc, notNullValue());

                 if (desc.contains("org.eclipse.mat.tests"))

@@ -237,7 +236,7 @@
                         try

                         {

                             collector.checkThat("Snapshot", answer, notNullValue());

-                            found++;

+                            incFound();

                             // Currently zipped hprof is very slow (>1 hour)

                             if (!compress || chunked)

                             {

@@ -264,8 +263,8 @@
         // See if any of the tests with any provider actually loads a dump

         if (num == nall)

         {

-            collector.checkThat("Available VMs", count, greaterThan(0));

-            collector.checkThat("Available dumps from VMs", found, greaterThan(0));

+            collector.checkThat("Available VMs", getCount(), greaterThan(0));

+            collector.checkThat("Available dumps from VMs", getFound(), greaterThan(0));

         }

     }

 

@@ -385,4 +384,24 @@
         }

         assertTrue(errMsg+" "+toFind, foundItem);

     }

+

+    static int getCount()

+    {

+        return count;

+    }

+

+    static void incCount()

+    {

+        ++count;

+    }

+

+    static int getFound()

+    {

+        return found;

+    }

+

+    static void incFound()

+    {

+        ++found;

+    }

 }

diff --git a/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/GeneralSnapshotTests.java b/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/GeneralSnapshotTests.java
index 25f9a1b..92eec6b 100644
--- a/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/GeneralSnapshotTests.java
+++ b/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/GeneralSnapshotTests.java
@@ -3,8 +3,8 @@
  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -12,7 +12,7 @@
  *    Andrew Johnson - test class specific name for Strings etc.

  *******************************************************************************/

 package org.eclipse.mat.tests.snapshot;

-
+

 import static org.hamcrest.CoreMatchers.anyOf;

 import static org.hamcrest.CoreMatchers.containsString;

 import static org.hamcrest.CoreMatchers.either;

@@ -1146,10 +1146,13 @@
     /**

      * Test exporting as HPROF

      * @param compress whether to compress the generated HPROF file

+     * @param chunked gzip in chunks for faster seeks

+     * @param redact whether to remove certain parts of the snapshot

+     * @param segsize

      * @throws SnapshotException

      * @throws IOException

      */

-    public void exportHPROF(boolean compress, boolean redact, long segsize) throws SnapshotException, IOException

+    public void exportHPROF(boolean compress, boolean chunked, boolean redact, long segsize) throws SnapshotException, IOException

     {

         // Currently can't export PHD

         assumeThat(snapshot.getSnapshotInfo().getProperty("$heapFormat"), not(equalTo((Serializable)"DTFJ-PHD")));

@@ -1164,6 +1167,7 @@
         try {

             SnapshotQuery query = SnapshotQuery.parse("export_hprof -output "+newSnapshotFile.getPath() +

                             (compress ? " -compress" : "") +

+                            (chunked ? " -chunked" : "") +

                             (mapping != null ? " -redact NAMES -map "+mapping.getPath() : "") +

                             (segsize > 0 ? " -segsize "+segsize : ""), snapshot);

             IResult t = query.execute(new CheckedProgressListener(collector));

@@ -1312,7 +1316,7 @@
     @Test

     public void exportHPROF() throws SnapshotException, IOException

     {

-        exportHPROF(false, false, 0);

+        exportHPROF(false, false, false, 0);

     }

 

     /**

@@ -1323,7 +1327,7 @@
     @Test

     public void exportHPROFredact() throws SnapshotException, IOException

     {

-        exportHPROF(false, true, 0);

+        exportHPROF(false, false, true, 0);

     }

 

     /**

@@ -1334,7 +1338,18 @@
     @Test

     public void exportHPROFCompress() throws SnapshotException, IOException

     {

-        exportHPROF(true, false, 0);

+        exportHPROF(true, false, false, 0);

+    }

+

+    /**

+     * Test exporting as compressed, chunked HPROF

+     * @throws SnapshotException

+     * @throws IOException

+     */

+    @Test

+    public void exportHPROFCompressChunked() throws SnapshotException, IOException

+    {

+        exportHPROF(true, true, false, 0);

     }

 

     /**

@@ -1347,7 +1362,7 @@
     @Test

     public void exportHPROFSegments() throws SnapshotException, IOException

     {

-        exportHPROF(false, false, 1000000);

+        exportHPROF(false, false, false, 1000000);

     }

 

     /**

diff --git a/plugins/org.eclipse.mat.ui.help/extrabuild.xml b/plugins/org.eclipse.mat.ui.help/extrabuild.xml
index 6c33d71..61c0b38 100644
--- a/plugins/org.eclipse.mat.ui.help/extrabuild.xml
+++ b/plugins/org.eclipse.mat.ui.help/extrabuild.xml
@@ -48,7 +48,7 @@
             <!-- Change to the version with which we build standalone MAT -->

             <link href="https://help.eclipse.org/2020-03/topic/org.eclipse.platform.doc.isv/reference/api/" />

             <link href="https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/" />

-            <link href="https://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.api.80.doc/com.ibm.dtfj/" />

+            <link href="https://www.ibm.com/docs/api/v1/content/SSYKE2_8.0.0/openj9/api/jdk8/platform/dtfj/" />

             <packageset dir="../org.eclipse.mat.report/src" defaultexcludes="yes">

               <include name="**"/>

             </packageset>

diff --git a/plugins/org.eclipse.mat.ui.help/mimes/i-export_txt.png b/plugins/org.eclipse.mat.ui.help/mimes/i-export_txt.png
new file mode 100644
index 0000000..1313a8d
--- /dev/null
+++ b/plugins/org.eclipse.mat.ui.help/mimes/i-export_txt.png
Binary files differ
diff --git a/plugins/org.eclipse.mat.ui.help/reference/iconassist.dita b/plugins/org.eclipse.mat.ui.help/reference/iconassist.dita
index db7132a..2197643 100644
--- a/plugins/org.eclipse.mat.ui.help/reference/iconassist.dita
+++ b/plugins/org.eclipse.mat.ui.help/reference/iconassist.dita
@@ -392,6 +392,14 @@
 					<stentry>Export to .html</stentry>

 				</strow>

 				<strow>

+					<stentry>

+						<image href="../mimes/i-export_txt.png">

+							<alt>Export to TXT icon</alt>

+						</image>

+					</stentry>

+					<stentry>Export to .txt</stentry>

+				</strow>

+				<strow>

 					<stentry></stentry>

 					<stentry>

 						<b>Views</b>

diff --git a/plugins/org.eclipse.mat.ui.help/reference/iconassist.html b/plugins/org.eclipse.mat.ui.help/reference/iconassist.html
index 945e7dd..b6e7215 100644
--- a/plugins/org.eclipse.mat.ui.help/reference/iconassist.html
+++ b/plugins/org.eclipse.mat.ui.help/reference/iconassist.html
@@ -392,6 +392,14 @@
 
 				</tr>
 <tr class="strow">
+					<td valign="top" headers="d3303e31" class="stentry">
+						<img class="image" src="../mimes/i-export_txt.png" alt="Export to TXT icon"/>
+					</td>
+
+					<td valign="top" headers="d3303e34" class="stentry">Export to .txt</td>
+
+				</tr>
+<tr class="strow">
 					<td valign="top" headers="d3303e31" class="stentry"> </td>
 
 					<td valign="top" headers="d3303e34" class="stentry">
diff --git a/plugins/org.eclipse.mat.ui.help/tasks/acquiringheapdump.dita b/plugins/org.eclipse.mat.ui.help/tasks/acquiringheapdump.dita
index 33a5723..2632023 100644
--- a/plugins/org.eclipse.mat.ui.help/tasks/acquiringheapdump.dita
+++ b/plugins/org.eclipse.mat.ui.help/tasks/acquiringheapdump.dita
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>

 <!--

-    Copyright (c) 2008, 2020 SAP AG and IBM Corporation.

+    Copyright (c) 2008, 2021 SAP AG and IBM Corporation.

     All rights reserved. This program and the accompanying materials

     are made available under the terms of the Eclipse Public License 2.0

     which accompanies this distribution, and is available at

@@ -19,7 +19,7 @@
 		<copyright>

 			<copyryear year=""></copyryear>

 			<copyrholder>

-				Copyright (c) 2008, 2020 SAP AG and IBM Corporation.

+				Copyright (c) 2008, 2021 SAP AG and IBM Corporation.

 			    All rights reserved. This program and the accompanying materials

 			    are made available under the terms of the Eclipse Public License 2.0

 			    which accompanies this distribution, and is available at

@@ -34,8 +34,8 @@
 			<!-- ***************************************************************

 			* HPROF dumps

 			****************************************************************** -->

-		    <p><b>HPROF Binary Heap Dumps</b></p>

-		    <p><i>Get Heap Dump on an OutOfMemoryError</i></p>

+			<p><b>HPROF Binary Heap Dumps</b></p>

+			<p><i>Get Heap Dump on an OutOfMemoryError</i></p>

 			<p> One can get a HPROF binary heap dump on an OutOfMemoryError for Sun JVM

 				(1.4.2_12 or higher and 1.5.0_07 or higher), Oracle JVMs,

 				OpenJDK JVMs,

@@ -155,8 +155,8 @@
 			</p>

 			

 			<p>Acquiring the heap dump is VM specific. Memory Analyzer comes with 

-			several so called heap dump providers - for Oracle and Sun based VMs 

-			(needs a Oracle or Sun JDK

+			several so called heap dump providers - for OpenJDK, Oracle and Sun based VMs 

+			(needs a OpenJDK, Oracle or Sun JDK

 			with jmap) and for IBM VMs (needs an IBM JDK or JRE). 

 			Also extension points 

 			are provided for adopters to plug-in their own heap dump providers.

@@ -240,19 +240,24 @@
 	<p>

 		<dl>

 			<dlentry>

-				<dt id="1">HPROF jmp dump provider</dt>

+				<dt id="1">HPROF jmap dump provider</dt>

 				<dd>

 					This provider uses the

 					<cmdname>jps</cmdname>

-					command supplied with an Oracle or OpenJDK based JDK to list the

+					command supplied with an OpenJDK or Oracle based JDK to list the

 					running JVMs on the system. The provider then uses the

 					<cmdname>jmap</cmdname>

 					command to get the chosen

-					JVM to generate an HPROF dump. This

+					JVM to generate an HPROF dump.

+					As an alternative the provider can use the <cmdname>jcmd</cmdname>

+					to both list running JVMs and to generate dumps.

+					This

 					provider requires a JDK (Java

 					development kit), not a JRE

 					(Java

-					runtime environment) for those two commands. IBM JDKs do not

+					runtime environment) for those commands. 

+					

+					IBM JDKs do not

 					have

 					the

 					<cmdname>jps</cmdname>

@@ -285,7 +290,7 @@
 					in

 					<codeph>tools.jar</codeph>

 					and not as part of JREs. Therefore if Memory Analyzer is run with

-					an Oracle JRE

+					an OpenJDK or Oracle JRE

 					then this dump provider will not be available.

 					The

 					<apiname>com.sun.tools.attach</apiname>

@@ -310,8 +315,8 @@
 			<dlentry id="3">

 				<dt>Attach API with helper JVM</dt>

 				<dd>

-					If Memory Analyzer is run with an Oracle JRE then this dump

-					provider can be used with an Oracle JDK by providing a path

+					If Memory Analyzer is run with an OpenJDK or Oracle JRE then this dump

+					provider can be used with an OpenJDK or Oracle JDK by providing a path

 					to a

 					<cmdname>java</cmdname>

 					executable. The dump provider will load the

@@ -320,7 +325,7 @@
 					so that the

 					<apiname>com.sun.tools.attach</apiname>

 					API

-					is acessible. This provider can also be used to list JVMs

+					is accessible. This provider can also be used to list JVMs

 					of a

 					different type from the JVM used to run Memory Analyzer.

 					For example

@@ -329,7 +334,13 @@
 					an IBM

 					JVM

 					<cmdname>java</cmdname>

-					command even when Memory Analyzer is run with an Oracle JVM.

+					command even when Memory Analyzer is run with an OpenJDK or Oracle JVM.

+					<p>

+					If a path to a

+					<cmdname>jcmd</cmdname>

+					executable is provided then this command will be used to

+					generate a list of running JVMs and to generate the dumps.

+					</p>

 				</dd>

 			</dlentry>

 		</dl>

@@ -432,6 +443,17 @@
 				</dd>

 			</dlentry>

 			<dlentry>

+				<dt>chunked</dt>

+				<dd>OpenJDK 15 and later can generate compressed HPROF files by

+				using the <cmdname>jcmd &lt;pid&gt; GC.heap_dump -gz=1</cmdname>

+				which compresses the HPROF file using gzip, but in chunks so

+				that random access to the file is quicker. Memory Analyzer version 1.12

+				and later can read this format, and with this option and

+				<option>compress</option> the HPROF dump provider

+				generates HPROF files compressed in chunks, for faster read access

+				than normal gzip compressed files.</dd>

+			</dlentry>

+			<dlentry>

 				<dt>live</dt>

 				<dd>On IBM JVMs this forces a garbage collection before a dump is

 					taken. This could affect

@@ -566,19 +588,20 @@
 					<colspec colname="COLSPEC6" colwidth="4*" />

 					<colspec colname="COLSPEC7" colwidth="2*" />

 					<colspec colname="COLSPEC8" colwidth="2*" />

-					<colspec colname="COLSPEC9" colwidth="4*" />

+					<colspec colname="COLSPEC9" colwidth="2*" />

 					<colspec colname="COLSPEC10" colwidth="4*" />

+					<colspec colname="COLSPEC11" colwidth="4*" />

 					<thead>

 						<row>

 							<entry colname="COLSPEC1" valign="top">Vendor</entry>

 							<entry colname="COLSPEC2" valign="top">Release</entry>

 							<entry namest="COLSPEC3" nameend="COLSPEC5" valign="top">VM

 								Parameter</entry>

-							<entry namest="COLSPEC6" nameend="COLSPEC7" valign="top">Sun

+							<entry namest="COLSPEC6" nameend="COLSPEC8" valign="top">JVM

 								Tools</entry>

-							<entry colname="COLSPEC8" valign="top">SAP Tool</entry>

-							<entry colname="COLSPEC9" valign="top">Attach</entry>

-							<entry colname="COLSPEC10" valign="top">MAT</entry>

+							<entry colname="COLSPEC9" valign="top">SAP Tool</entry>

+							<entry colname="COLSPEC10" valign="top">Attach</entry>

+							<entry colname="COLSPEC11" valign="top">MAT</entry>

 						</row>

 					</thead>

 					<tbody>

@@ -589,6 +612,7 @@
 							<entry colname="COLSPEC4">On Ctrl+Break</entry>

 							<entry>Agent</entry>

 							<entry>JMap</entry>

+							<entry>JCmd</entry>

 							<entry>JConsole</entry>

 							<entry>JVMMon</entry>

 							<entry>API</entry>

@@ -600,9 +624,10 @@
 							<entry>Yes</entry>

 							<entry>Yes</entry>

 							<entry>Yes</entry>

-							<entry />

-							<entry />

-							<entry />

+							<entry>No</entry>

+							<entry>No</entry>

+							<entry>No</entry>

+							<entry>No</entry>

 							<entry />

 							<entry>No</entry>

 						</row>

@@ -612,8 +637,9 @@
 							<entry>Yes (Since 1.5.0_15)</entry>

 							<entry>Yes</entry>

 							<entry>Yes (Only Solaris and Linux)</entry>

-							<entry />

-							<entry />

+							<entry>No</entry>

+							<entry>No</entry>

+							<entry>No</entry>

 							<entry>com.sun.tools.attach</entry>

 							<entry>Yes (Only Solaris and Linux)</entry>

 						</row>

@@ -623,27 +649,55 @@
 							<entry>No</entry>

 							<entry>Yes</entry>

 							<entry>Yes</entry>

+							<entry>No</entry>

+							<entry>Yes</entry>

+							<entry>No</entry>

+							<entry>com.sun.tools.attach</entry>

+							<entry>Yes</entry>

+						</row>

+						<row>

+							<entry>Oracle, OpenJDK, HP</entry>

+							<entry>1.7.0</entry>

+							<entry>Yes</entry>

+							<entry>No</entry>

+							<entry>Yes</entry>

+							<entry>Yes</entry>

+							<entry>Yes</entry>

 							<entry>Yes</entry>

 							<entry></entry>

 							<entry>com.sun.tools.attach</entry>

 							<entry>Yes</entry>

 						</row>

 						<row>

-							<entry morerows="1">Oracle, OpenJDK, HP</entry>

-							<entry>1.7.0</entry>

+							<entry morerows="2">Oracle, OpenJDK, HP, Amazon Corretto</entry>

+							<entry>1.8.0</entry>

 							<entry>Yes</entry>

 							<entry>No</entry>

 							<entry>Yes</entry>

 							<entry>Yes</entry>

 							<entry>Yes</entry>

+							<entry>Yes</entry>

+							<entry></entry>

+							<entry>com.sun.tools.attach</entry>

+							<entry>Yes</entry>

+						</row>

+						<row>

+							<entry>11</entry>

+							<entry>Yes</entry>

+							<entry>No</entry>

+							<entry>No</entry>

+							<entry>Yes</entry>

+							<entry>Yes</entry>

+							<entry>Yes</entry>

 							<entry></entry>

 							<entry>com.sun.tools.attach</entry>

 							<entry>Yes</entry>

 						</row>

 						<row>

-							<entry>1.8.0</entry>

+							<entry>15</entry>

 							<entry>Yes</entry>

 							<entry>No</entry>

+							<entry>No</entry>

 							<entry>Yes</entry>

 							<entry>Yes</entry>

 							<entry>Yes</entry>

@@ -658,7 +712,8 @@
 							<entry>Yes</entry>

 							<entry>Yes</entry>

 							<entry>Yes (Only Solaris and Linux)</entry>

-							<entry />

+							<entry>No</entry>

+							<entry>No</entry>

 							<entry>Yes</entry>

 							<entry></entry>

 							<entry />

@@ -672,6 +727,7 @@
 							<entry>No</entry>

 							<entry>No</entry>

 							<entry>No</entry>

+							<entry>No</entry>

 							<entry></entry>

 							<entry>No</entry>

 						</row>

@@ -683,6 +739,7 @@
 							<entry>No</entry>

 							<entry>No</entry>

 							<entry>No</entry>

+							<entry>No</entry>

 							<entry>com.ibm.tools.attach</entry>

 							<entry>No</entry>

 						</row>

@@ -694,6 +751,7 @@
 							<entry>No</entry>

 							<entry>No</entry>

 							<entry>No</entry>

+							<entry>No</entry>

 							<entry>com.ibm.tools.attach</entry>

 							<entry>No</entry>

 						</row>

@@ -705,6 +763,7 @@
 							<entry>No</entry>

 							<entry>No</entry>

 							<entry>No</entry>

+							<entry>No</entry>

 							<entry>com.ibm.tools.attach</entry>

 							<entry>Yes</entry>

 						</row>

@@ -716,6 +775,7 @@
 							<entry>No</entry>

 							<entry>No</entry>

 							<entry>No</entry>

+							<entry>No</entry>

 							<entry>com.ibm.tools.attach</entry>

 							<entry>Yes</entry>

 						</row>

@@ -727,6 +787,7 @@
 							<entry>No</entry>

 							<entry>No</entry>

 							<entry>No</entry>

+							<entry>No</entry>

 							<entry>com.ibm.tools.attach</entry>

 							<entry>Yes</entry>

 						</row>

@@ -737,17 +798,31 @@
 							<entry>No</entry>

 							<entry>No</entry>

 							<entry>No</entry>

+							<entry>Yes (PHD only?)</entry>

 							<entry>No</entry>

 							<entry>com.sun.tools.attach</entry>

 							<entry>Yes</entry>

 						</row>

 						<row>

-							<entry>OpenJ9</entry>

+							<entry morerows="1">OpenJ9</entry>

 							<entry>1.8.0</entry>

 							<entry>Yes</entry>

 							<entry>Yes</entry>

 							<entry>No</entry>

+							<entry>Yes</entry>

+							<entry>Yes</entry>

+							<entry>Yes (PHD only)</entry>

 							<entry>No</entry>

+							<entry>com.sun.tools.attach</entry>

+							<entry>Yes</entry>

+						</row>

+						<row>

+							<entry>11</entry>

+							<entry>Yes</entry>

+							<entry>Yes</entry>

+							<entry>No</entry>

+							<entry>Yes</entry>

+							<entry>Yes</entry>

 							<entry>Yes (PHD only)</entry>

 							<entry>No</entry>

 							<entry>com.sun.tools.attach</entry>

diff --git a/plugins/org.eclipse.mat.ui.help/tasks/acquiringheapdump.html b/plugins/org.eclipse.mat.ui.help/tasks/acquiringheapdump.html
index 781babb..bb1267c 100644
--- a/plugins/org.eclipse.mat.ui.help/tasks/acquiringheapdump.html
+++ b/plugins/org.eclipse.mat.ui.help/tasks/acquiringheapdump.html
@@ -6,8 +6,8 @@
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <meta name="DC.Type" content="task"/>
 <meta name="DC.Title" content="Acquiring Heap Dumps"/>
-<meta name="copyright" content="Copyright (c) 2008, 2020 SAP AG and IBM Corporation. All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ " type="primary"/>
-<meta name="DC.Rights.Owner" content="Copyright (c) 2008, 2020 SAP AG and IBM Corporation. All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ " type="primary"/>
+<meta name="copyright" content="Copyright (c) 2008, 2021 SAP AG and IBM Corporation. All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ " type="primary"/>
+<meta name="DC.Rights.Owner" content="Copyright (c) 2008, 2021 SAP AG and IBM Corporation. All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ " type="primary"/>
 <meta name="DC.Format" content="XHTML"/>
 <meta name="DC.Identifier" content="task_acquiringheapdump"/>
 <meta name="DC.Language" content="en-us"/>
@@ -25,9 +25,9 @@
 		<div class="section context">
 		
 			
-		    <p class="p"><strong class="ph b">HPROF Binary Heap Dumps</strong></p>
+			<p class="p"><strong class="ph b">HPROF Binary Heap Dumps</strong></p>
 
-		    <p class="p"><em class="ph i">Get Heap Dump on an OutOfMemoryError</em></p>
+			<p class="p"><em class="ph i">Get Heap Dump on an OutOfMemoryError</em></p>
 
 			<p class="p"> One can get a HPROF binary heap dump on an OutOfMemoryError for Sun JVM
 				(1.4.2_12 or higher and 1.5.0_07 or higher), Oracle JVMs,
@@ -175,8 +175,8 @@
 
 			
 			<p class="p">Acquiring the heap dump is VM specific. Memory Analyzer comes with 
-			several so called heap dump providers - for Oracle and Sun based VMs 
-			(needs a Oracle or Sun JDK
+			several so called heap dump providers - for OpenJDK, Oracle and Sun based VMs 
+			(needs a OpenJDK, Oracle or Sun JDK
 			with jmap) and for IBM VMs (needs an IBM JDK or JRE). 
 			Also extension points 
 			are provided for adopters to plug-in their own heap dump providers.
@@ -253,20 +253,25 @@
 	<div class="p">
 		<dl class="dl">
 			
-				<dt class="dt dlterm" id="task_acquiringheapdump__1">HPROF jmp dump provider</dt>
+				<dt class="dt dlterm" id="task_acquiringheapdump__1">HPROF jmap dump provider</dt>
 
 				<dd class="dd">
 					This provider uses the
 					<span class="keyword cmdname">jps</span>
-					command supplied with an Oracle or OpenJDK based JDK to list the
+					command supplied with an OpenJDK or Oracle based JDK to list the
 					running JVMs on the system. The provider then uses the
 					<span class="keyword cmdname">jmap</span>
 					command to get the chosen
-					JVM to generate an HPROF dump. This
+					JVM to generate an HPROF dump.
+					As an alternative the provider can use the <span class="keyword cmdname">jcmd</span>
+					to both list running JVMs and to generate dumps.
+					This
 					provider requires a JDK (Java
 					development kit), not a JRE
 					(Java
-					runtime environment) for those two commands. IBM JDKs do not
+					runtime environment) for those commands. 
+					
+					IBM JDKs do not
 					have
 					the
 					<span class="keyword cmdname">jps</span>
@@ -299,7 +304,7 @@
 					in
 					<samp class="ph codeph">tools.jar</samp>
 					and not as part of JREs. Therefore if Memory Analyzer is run with
-					an Oracle JRE
+					an OpenJDK or Oracle JRE
 					then this dump provider will not be available.
 					The
 					<span class="keyword apiname">com.sun.tools.attach</span>
@@ -326,8 +331,8 @@
 				<dt class="dt dlterm"><a name="task_acquiringheapdump__3"><!-- --></a>Attach API with helper JVM</dt>
 
 				<dd class="dd">
-					If Memory Analyzer is run with an Oracle JRE then this dump
-					provider can be used with an Oracle JDK by providing a path
+					If Memory Analyzer is run with an OpenJDK or Oracle JRE then this dump
+					provider can be used with an OpenJDK or Oracle JDK by providing a path
 					to a
 					<span class="keyword cmdname">java</span>
 					executable. The dump provider will load the
@@ -336,7 +341,7 @@
 					so that the
 					<span class="keyword apiname">com.sun.tools.attach</span>
 					API
-					is acessible. This provider can also be used to list JVMs
+					is accessible. This provider can also be used to list JVMs
 					of a
 					different type from the JVM used to run Memory Analyzer.
 					For example
@@ -345,7 +350,14 @@
 					an IBM
 					JVM
 					<span class="keyword cmdname">java</span>
-					command even when Memory Analyzer is run with an Oracle JVM.
+					command even when Memory Analyzer is run with an OpenJDK or Oracle JVM.
+					<p class="p">
+					If a path to a
+					<span class="keyword cmdname">jcmd</span>
+					executable is provided then this command will be used to
+					generate a list of running JVMs and to generate the dumps.
+					</p>
+
 				</dd>
 
 			
@@ -467,6 +479,19 @@
 
 			
 			
+				<dt class="dt dlterm">chunked</dt>
+
+				<dd class="dd">OpenJDK 15 and later can generate compressed HPROF files by
+				using the <span class="keyword cmdname">jcmd &lt;pid&gt; GC.heap_dump -gz=1</span>
+				which compresses the HPROF file using gzip, but in chunks so
+				that random access to the file is quicker. Memory Analyzer version 1.12
+				and later can read this format, and with this option and
+				<span class="keyword option">compress</span> the HPROF dump provider
+				generates HPROF files compressed in chunks, for faster read access
+				than normal gzip compressed files.</dd>
+
+			
+			
 				<dt class="dt dlterm">live</dt>
 
 				<dd class="dd">On IBM JVMs this forces a garbage collection before a dump is
@@ -619,23 +644,24 @@
 					
 					
 					
+					
 					<thead class="thead" align="left">
 						<tr class="row">
-							<th class="entry" valign="top" width="6.25%" id="d11477e584">Vendor</th>
+							<th class="entry" valign="top" width="5.88235294117647%" id="d11625e611">Vendor</th>
 
-							<th class="entry" valign="top" width="12.5%" id="d11477e587">Release</th>
+							<th class="entry" valign="top" width="11.76470588235294%" id="d11625e614">Release</th>
 
-							<th class="entry" colspan="3" valign="top" id="d11477e590">VM
+							<th class="entry" colspan="3" valign="top" id="d11625e617">VM
 								Parameter</th>
 
-							<th class="entry" colspan="2" valign="top" id="d11477e593">Sun
+							<th class="entry" colspan="3" valign="top" id="d11625e620">JVM
 								Tools</th>
 
-							<th class="entry" valign="top" width="6.25%" id="d11477e596">SAP Tool</th>
+							<th class="entry" valign="top" width="5.88235294117647%" id="d11625e623">SAP Tool</th>
 
-							<th class="entry" valign="top" width="12.5%" id="d11477e600">Attach</th>
+							<th class="entry" valign="top" width="11.76470588235294%" id="d11625e627">Attach</th>
 
-							<th class="entry" valign="top" width="12.5%" id="d11477e603">MAT</th>
+							<th class="entry" valign="top" width="11.76470588235294%" id="d11625e630">MAT</th>
 
 						</tr>
 
@@ -643,329 +669,430 @@
 
 					<tbody class="tbody">
 						<tr class="row">
-							<td class="entry" valign="top" width="6.25%" headers="d11477e584 "> </td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e611 "> </td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 "> </td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 "> </td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">On out of memory</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">On out of memory</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">On Ctrl+Break</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">On Ctrl+Break</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">Agent</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">Agent</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">JMap</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">JMap</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">JConsole</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">JCmd</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 ">JVMMon</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">JConsole</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">API</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">JVMMon</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">acquire heap dump</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">API</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">acquire heap dump</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" rowspan="3" valign="top" width="6.25%" headers="d11477e584 ">Sun, HP</td>
+							<td class="entry" rowspan="3" valign="top" width="5.88235294117647%" headers="d11625e611 ">Sun, HP</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.4.2_12</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.4.2_12</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 "> </td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 "> </td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 "> </td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 "> </td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 "> </td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">No</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.5.0_07</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.5.0_07</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes (Since 1.5.0_15)</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes (Since 1.5.0_15)</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">Yes (Only Solaris and Linux)</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">Yes (Only Solaris and Linux)</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 "> </td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 "> </td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">com.sun.tools.attach</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">Yes (Only Solaris and Linux)</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.sun.tools.attach</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes (Only Solaris and Linux)</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.6.0_00</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.6.0_00</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 "> </td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">com.sun.tools.attach</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.sun.tools.attach</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" rowspan="2" valign="top" width="6.25%" headers="d11477e584 ">Oracle, OpenJDK, HP</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e611 ">Oracle, OpenJDK, HP</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.7.0</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.7.0</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 "> </td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">com.sun.tools.attach</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 "> </td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.sun.tools.attach</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.8.0</td>
+							<td class="entry" rowspan="3" valign="top" width="5.88235294117647%" headers="d11625e611 ">Oracle, OpenJDK, HP, Amazon Corretto</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.8.0</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 "> </td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">com.sun.tools.attach</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 "> </td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.sun.tools.attach</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" valign="top" width="6.25%" headers="d11477e584 ">SAP</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">11</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">Any 1.5.0</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">Yes (Only Solaris and Linux)</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 "> </td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 "> </td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 "> </td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.sun.tools.attach</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 "> </td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" rowspan="7" valign="top" width="6.25%" headers="d11477e584 ">IBM</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">15</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.4.2 SR12</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 "> </td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 "> </td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.sun.tools.attach</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.5.0 SR8a</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e611 ">SAP</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">Any 1.5.0</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">Yes (Only Solaris and Linux)</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">com.ibm.tools.attach</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">Yes</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 "> </td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 "> </td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.6.0 SR2</td>
+							<td class="entry" rowspan="7" valign="top" width="5.88235294117647%" headers="d11625e611 ">IBM</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.4.2 SR12</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">com.ibm.tools.attach</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 "> </td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">No</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.6.0 SR6</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.5.0 SR8a</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">com.ibm.tools.attach</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.ibm.tools.attach</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">No</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.7.0</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.6.0 SR2</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">com.ibm.tools.attach</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.ibm.tools.attach</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">No</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.8.0</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.6.0 SR6</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">com.ibm.tools.attach</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.ibm.tools.attach</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.8.0 SR5</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.7.0</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">com.sun.tools.attach</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.ibm.tools.attach</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes</td>
 
 						</tr>
 
 						<tr class="row">
-							<td class="entry" valign="top" width="6.25%" headers="d11477e584 ">OpenJ9</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.8.0</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e587 ">1.8.0</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e590 ">Yes</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e590 ">No</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e593 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e593 ">Yes (PHD only)</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
 
-							<td class="entry" valign="top" width="6.25%" headers="d11477e596 ">No</td>
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e600 ">com.sun.tools.attach</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.ibm.tools.attach</td>
 
-							<td class="entry" valign="top" width="12.5%" headers="d11477e603 ">Yes</td>
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes</td>
+
+						</tr>
+
+						<tr class="row">
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.8.0 SR5</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">No</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">No</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">No</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes (PHD only?)</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.sun.tools.attach</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes</td>
+
+						</tr>
+
+						<tr class="row">
+							<td class="entry" rowspan="2" valign="top" width="5.88235294117647%" headers="d11625e611 ">OpenJ9</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">1.8.0</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">No</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">Yes</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes (PHD only)</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.sun.tools.attach</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes</td>
+
+						</tr>
+
+						<tr class="row">
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e614 ">11</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e617 ">Yes</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e617 ">No</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e620 ">Yes</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e620 ">Yes (PHD only)</td>
+
+							<td class="entry" valign="top" width="5.88235294117647%" headers="d11625e623 ">No</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e627 ">com.sun.tools.attach</td>
+
+							<td class="entry" valign="top" width="11.76470588235294%" headers="d11625e630 ">Yes</td>
 
 						</tr>
 
diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/Messages.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/Messages.java
index 26b701f..6c8e7c6 100644
--- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/Messages.java
+++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/Messages.java
@@ -99,7 +99,6 @@
     public static String ExportActions_ExportToHTML;

     public static String ExportActions_ExportToTxt;

     public static String ExportActions_PlainText;

-    public static String ExportActions_PlainText2;

     public static String ExportActions_ZippedWebPage;

     public static String FieldsContentProvider_Displayed;

     public static String FileOpenDialogEditor_ChooseFile;

diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/acquire/AcquireDialog.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/acquire/AcquireDialog.java
index c355e87..39d8df1 100644
--- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/acquire/AcquireDialog.java
+++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/acquire/AcquireDialog.java
@@ -1,10 +1,10 @@
 /*******************************************************************************

- * Copyright (c) 2009, 2019 SAP AG and IBM Corporation.

+ * Copyright (c) 2009, 2021 SAP AG and IBM Corporation.

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -143,7 +143,7 @@
         });

 

         final int descWidth = 250;

-        final int pidWidth = 50;

+        final int pidWidth = 70;

         final int provWidth = 200;

         TableColumn column = new TableColumn(localVMsTable, SWT.RIGHT);

         column.setText(Messages.AcquireDialog_ColumnDescription);

diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/ExportActions.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/ExportActions.java
index 5c95474..3b3f6d6 100644
--- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/ExportActions.java
+++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/ExportActions.java
@@ -42,7 +42,6 @@
 import org.eclipse.mat.ui.Messages;

 import org.eclipse.mat.ui.internal.viewer.RefinedResultViewer.ControlItem;

 import org.eclipse.mat.ui.internal.viewer.RefinedResultViewer.Key;

-import org.eclipse.mat.ui.util.Copy;

 import org.eclipse.mat.ui.util.ErrorHelper;

 import org.eclipse.mat.ui.util.ProgressMonitorWrapper;

 import org.eclipse.mat.util.MessageUtil;

@@ -88,7 +87,7 @@
             final int limit = (controlItem != null && controlItem.getTotals() != null) ? controlItem.getTotals()

                             .getVisibleItems() : 25;

 

-            expandedTree(control, result);

+            selectedExpanded(control, result);

 

             new Job(Messages.ExportActions_ExportHTML)

             {

@@ -119,7 +118,7 @@
         }

     }

 

-    private static void expandedTree(Control control, RefinedStructuredResult result)

+    private static void selectedExpanded(Control control, RefinedStructuredResult result)

     {

         // extract expanded items

 

@@ -282,20 +281,14 @@
         public void run()

         {

             ExportDialog dialog = new ExportDialog(control.getShell(), //

-                            new String[] { Messages.ExportActions_PlainText, Messages.ExportActions_PlainText2 }, //

-                            new String[] { "*.txt", "*.txt" });//$NON-NLS-1$ //$NON-NLS-2$

+                            new String[] { Messages.ExportActions_PlainText }, //

+                            new String[] { "*.txt"});//$NON-NLS-1$ //$NON-NLS-2$

             final String fileName = dialog.open();

             if (fileName == null)

                 return;

 

-            // Old version of export

-            if (dialog.dlg.getFilterIndex() < 1) {

-                Copy.exportToTxtFile(control, fileName);

-                return;

-            }

-

             if (result instanceof RefinedStructuredResult)

-                expandedTree(control, (RefinedStructuredResult)result);

+                selectedExpanded(control, (RefinedStructuredResult)result);

 

             new Job(Messages.ExportActions_ExportTXT)

             {

diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/messages.properties b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/messages.properties
index e102e82..573ff40 100644
--- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/messages.properties
+++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/messages.properties
@@ -121,7 +121,6 @@
 ExportActions_ExportToHTML=Export to HTML...

 ExportActions_ExportToTxt=Export to TXT...

 ExportActions_PlainText=Plain Text(*.txt)

-ExportActions_PlainText2=Plain Text(*.txt) - new version

 ExportActions_ZippedWebPage=Zipped Web Page (*.zip)

 FieldsContentProvider_Displayed={0} out of {1} displayed

 FileOpenDialogEditor_ChooseFile=Choose File...

diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/Copy.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/Copy.java
index cde1d70..ca19ac9 100644
--- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/Copy.java
+++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/Copy.java
@@ -14,15 +14,15 @@
 package org.eclipse.mat.ui.util;

 

 import java.io.File;

-import java.io.FileWriter;

 import java.io.IOException;

-import java.io.PrintWriter;

 import java.io.StringWriter;

 import java.net.URL;

 import java.util.ArrayList;

 import java.util.Arrays;

+import java.util.Collections;

 import java.util.HashSet;

 import java.util.List;

+import java.util.Set;

 

 import org.eclipse.mat.query.Column;

 import org.eclipse.mat.query.Column.Alignment;

@@ -35,9 +35,7 @@
 import org.eclipse.mat.query.ResultMetaData;

 import org.eclipse.mat.report.IOutputter;

 import org.eclipse.mat.report.RendererRegistry;

-import org.eclipse.mat.report.internal.TextEmitter;

 import org.eclipse.mat.ui.MemoryAnalyserPlugin;

-import org.eclipse.mat.ui.Messages;

 import org.eclipse.swt.SWT;

 import org.eclipse.swt.dnd.Clipboard;

 import org.eclipse.swt.dnd.TextTransfer;

@@ -52,7 +50,7 @@
 import org.eclipse.swt.widgets.TreeColumn;

 import org.eclipse.swt.widgets.TreeItem;

 

-public abstract class Copy extends TextEmitter

+public abstract class Copy

 {

     protected Control control;

     protected Item[] selection;

@@ -65,23 +63,11 @@
         new CopyToClipboard(control, selection).doCopy();

     }

 

-    public static void exportToTxtFile(Control control, String fileName)

+    public static void copyToClipboard(String text, Display display)

     {

-        PrintWriter writer = null;

-        try

-        {

-            writer = new PrintWriter(new FileWriter(fileName));

-            new ExportToFile(control, null, writer).doCopy();

-        }

-        catch (IOException e)

-        {

-            throw new RuntimeException(Messages.Copy_ErrorInExport, e);

-        }

-        finally

-        {

-            if (writer != null)

-                writer.close();

-        }

+        Clipboard clipboard = new Clipboard(display);

+        clipboard.setContents(new Object[] { text.toString() }, new Transfer[] { TextTransfer.getInstance() });

+        clipboard.dispose();

     }

 

     // //////////////////////////////////////////////////////////////

@@ -94,345 +80,12 @@
         this.selection = selection != null && selection.length > 0 ? selection : null;

     }

 

-    @Override

-    protected boolean shouldAddNextLine(Object item)

-    {

-        return item instanceof TreeItem && ((TreeItem) item).getExpanded() && toPrint((TreeItem) item);

-    }

-

-    @Override

-    protected String getItemValue(Object item, int columnIndex)

-    {

-        String value = "";//$NON-NLS-1$

-        if (item instanceof TableItem)

-        {

-            value = ((TableItem) item).getText(columnIndex);

-        }

-        else if ((item instanceof TreeItem) && toPrint((TreeItem) item))

-        {

-            value = ((TreeItem) item).getText(columnIndex);

-        }

-        return value;

-    }

-

-    @Override

-    protected boolean shouldSuppressLineBreak(Object item)

-    {

-        if (item instanceof TableItem)

-        {}

-        else if ((item instanceof TreeItem) && toPrint((TreeItem) item))

-        {}

-        else if ((item instanceof TreeItem) && !toPrint((TreeItem) item))

-        { return true; }

-        return false;

-    }

-

-    @Override

-    protected Object[] getItems()

-    {

-        Object[] items;

-        if (selection != null)

-            items = selection;

-        else if (control instanceof Table)

-            items = ((Table) control).getItems();

-        else

-            // if (copyData.control instanceof Tree)

-            items = ((Tree) control).getItems();

-        return items;

-    }

-

-    @Override

-    protected void findColumnOrderAndAlignment(Object[] columns)

-    {

-        // Find the alignment and order of the columns

-        align = new int[columns.length];

-        if (control instanceof Table)

-        {

-            Table table = (Table) control;

-            order = table.getColumnOrder();

-            for (int i = 0; i < columns.length; ++i)

-            {

-                align[i] = table.getColumn(i).getAlignment();

-            }

-        }

-        else

-        {

-            Tree tree = (Tree) control;

-            order = tree.getColumnOrder();

-            for (int i = 0; i < columns.length; ++i)

-            {

-                align[i] = tree.getColumn(i).getAlignment();

-            }

-        }

-    }

-

-    @Override

-    protected String getDisplayableColumnValueInSimpleStructure(Object item)

-    {

-        String value = "";//$NON-NLS-1$

-        if (item instanceof TableItem)

-        {

-            value = ((TableItem) item).getText();

-        }

-        else if ((item instanceof TreeItem) && toPrint((TreeItem) item))

-        {

-            value = ((TreeItem) item).getText();

-        }

-        return value;

-    }

-

-    @Override

-    protected boolean isAlignmentRight(int alignment)

-    {

-        return alignment == SWT.RIGHT;

-    }

-

-    @Override

-    protected boolean isAlignmentCenter(int alignment)

-    {

-        return alignment == SWT.CENTER;

-    }

-

-    @Override

-    protected Object[] getColumns()

-    {

-        if (control instanceof Table)

-            return ((Table) control).getColumns();

-        else

-            // Tree

-            return ((Tree) control).getColumns();

-    }

-

-    @Override

-    protected String getColumnName(Object column)

-    {

-        return ((Item) column).getText();

-    }

-

-    @Override

-    protected String getDisplayableRowValue(Object item)

-    {

-        return ((TreeItem) item).getText();

-    }

-

-    @Override

-    protected String getDisplayableColumnValue(Object item, int index)

-    {

-        return ((TreeItem) item).getText(index);

-    }

-

-    @Override

-    protected boolean isExpanded(Object item)

-    {

-        return ((TreeItem) item).getExpanded();

-    }

-

-    @Override

-    protected int getColumnLength(Object[] items, Object[] objColumns, int columnNumber)

-    {

-        int lengthToCompare = 0;

-        Item[] columns = (Item[]) objColumns;

-        String header = columns[columnNumber].getText();

-        int length = header != null ? header.length() : 0;

-

-        for (int i = 0; i < items.length; i++)

-        {

-            if (items[i] instanceof TableItem)

-                lengthToCompare = ((TableItem) items[i]).getText(columnNumber).length();

-

-            else

-                lengthToCompare = ((TreeItem) items[i]).getText(columnNumber).length();

-

-            if (lengthToCompare > length)

-                length = lengthToCompare;

-

-            if (items[i] instanceof TreeItem && ((TreeItem) items[i]).getExpanded())

-            {

-                if (columnNumber == order[0])

-                    lengthToCompare = compare((TreeItem) items[i], length, columnNumber, new StringBuilder());

-                else

-                    lengthToCompare = getOtherColumnLength((TreeItem) items[i], length, columnNumber);

-

-            }

-            if (lengthToCompare > length)

-                length = lengthToCompare;

-        }

-

-        return length;

-    }

-

-    @Override

-    protected Object[] getChildren(Object item)

-    {

-        return ((TreeItem) item).getItems();

-    }

-

-    private int getOtherColumnLength(TreeItem item, int length, int columnNumber)

-    {

-        int lengthToCompare = 0;

-        TreeItem[] children = item.getItems();

-        for (int i = 0; i < children.length; i++)

-        {

-            if (selection != null && skip(children[i]))

-                continue;

-            String columnText = children[i].getText(columnNumber);

-            if (columnText != null)

-                lengthToCompare = columnText.length();

-            if (lengthToCompare > length)

-                length = lengthToCompare;

-

-            if (children[i].getExpanded())

-            {

-                lengthToCompare = getOtherColumnLength(children[i], length, columnNumber);

-                if (lengthToCompare > length)

-                    length = lengthToCompare;

-            }

-

-        }

-        return length;

-    }

-

-    private int compare(TreeItem item, int length, int columnNumber, StringBuilder level)

-    {

-        int lengthToCompare = 0;

-        TreeItem[] children = item.getItems();

-        for (int i = 0; i < children.length; i++)

-        {

-            if (selection != null && skip(children[i]))

-                continue;

-            level = getLevel(level, children.length, i);

-            lengthToCompare = children[i].getText(columnNumber).length() + level.length();

-            if (lengthToCompare > length)

-                length = lengthToCompare;

-

-            if (children[i].getExpanded())

-            {

-                lengthToCompare = compare(children[i], length, columnNumber, level);

-                if (lengthToCompare > length)

-                    length = lengthToCompare;

-            }

-            if (level.length() >= 3)

-                level.delete(level.length() - 3, level.length());

-

-        }

-        return length;

-    }

-

-    /**

-     * Whether to print.

-     * If the parent of this item is in the selection, return false.

-     * @param item

-     * @return

-     */

-    private boolean toPrint(TreeItem item)

-    {

-        if (selection == null)

-            return true;

-        TreeItem[] selection = (TreeItem[]) this.selection;

-        for (TreeItem treeItem : selection)

-        {

-            if (treeItem.equals(item.getParentItem()))

-                return false;

-        }

-        return true;

-    }

-

-    /**

-     * See if item in the selection.

-     * @param item 

-     * @return true if not in the selection.

-     */

-    private boolean skip(TreeItem item)

-    {

-        TreeItem[] selection = (TreeItem[]) this.selection;

-        for (TreeItem treeItem : selection)

-        {

-            if (treeItem.equals(item))

-                return false;

-        }

-        return true;

-    }

-

-    @Override

-    protected boolean shouldProcessChild(Object child)

-    {

-        return selection == null || !skip((TreeItem) child);

-    }

-

-    private static class ExportToFile extends Copy

-    {

-        private PrintWriter writer;

-

-        public ExportToFile(Control control, Item[] selection, PrintWriter writer)

-        {

-            super(control, selection);

-            this.writer = writer;

-        }

-

-        @Override

-        protected void append(String string)

-        {

-            writer.write(string);

-        }

-

-        @Override

-        protected void done()

-        {

-            // flush the writer at the end

-            writer.flush();

-        }

-    }

-

     private static class CopyToClipboard extends Copy

     {

-        private StringBuilder buffer = new StringBuilder(); // a buffer to keep

-                                                            // the content for

-                                                            // the clipboard

-

         private CopyToClipboard(Control control, Item[] selection)

         {

             super(control, selection);

         }

-

-        @Override

-        protected void append(String string)

-        {

-            // just append everything to a buffer in memory

-            buffer.append(string);

-        }

-

-        @Override

-        protected void done()

-        {

-            // done -> just copy the buffer to the clipboard

-            copyToClipboard(buffer.toString(), control.getDisplay());

-        }

-    }

-

-    public static void copyToClipboard(String text, Display display)

-    {

-        Clipboard clipboard = new Clipboard(display);

-        clipboard.setContents(new Object[] { text.toString() }, new Transfer[] { TextTransfer.getInstance() });

-        clipboard.dispose();

-    }

-

-    public static void copyToClipboard2(Control control)

-    {

-        Item[] selection = (control instanceof Table) ? ((Table) control).getSelection() //

-                        : ((Tree) control).getSelection();

-

-        new CopyToClipboard2(control, selection).doCopy();

-    }

-

-    private static class CopyToClipboard2

-    {

-        protected Control control;

-        protected Item[] selection;

-        private CopyToClipboard2(Control control, Item[] selection)

-        {

-            this.control = control;

-            this.selection = selection;

-        }

         private void doCopy()

         {

             IResult t = control instanceof Table ? convert((Table)control) : convert((Tree)control);

@@ -452,184 +105,195 @@
                 return;

             }

         }

-

-        private IResultTable convert(Table ct)

-        {

-            IResultTable t = new IResultTable() {

-

-                @Override

-                public Column[] getColumns()

-                {

-                    TableColumn tcs[] = ct.getColumns();

-                    int order[] = ct.getColumnOrder();

-                    Column c[] = new Column[order.length];

-                    for (int i = 0; i < order.length; ++i)

-                    {

-                        int col = order[i];

-                        TableColumn tc = tcs[col];

-                        c[i] = new Column(tc.getText());

-                        switch (tc.getAlignment()) {

-                            case SWT.RIGHT:

-                                c[i].aligning(Alignment.RIGHT);

-                                break;

-                            case SWT.CENTER:

-                                c[i].aligning(Alignment.CENTER);

-                                break;

-                            case SWT.LEFT:

-                                c[i].aligning(Alignment.LEFT);

-                                break;

-                        }

-                    }

-                    return c;

-                }

-

-                @Override

-                public Object getColumnValue(Object row, int columnIndex)

-                {

-                    return ((TableItem)row).getText(ct.getColumnOrder()[columnIndex]);

-                }

-

-                @Override

-                public IContextObject getContext(Object row)

-                {

-                    return null;

-                }

-

-                @Override

-                public ResultMetaData getResultMetaData()

-                {

-                    return null;

-                }

-

-                @Override

-                public int getRowCount()

-                {

-                    return selection.length;

-                }

-

-                @Override

-                public Object getRow(int rowId)

-                {

-                    return selection[rowId];

-                }

-

-            };

-            return t;

-        }

-

-        interface IRTS extends IResultTree, ISelectionProvider {};

-        private IResultTree convert(Tree ct)

-        {

-            final HashSet<Item> selset = new HashSet<Item>(Arrays.asList(selection));

-            IResultTree t = new IRTS() {

-

-                @Override

-                public Column[] getColumns()

-                {

-                    TreeColumn tcs[] = ct.getColumns();

-                    int order[] = ct.getColumnOrder();

-                    Column c[] = new Column[tcs.length];

-                    for (int i = 0; i < order.length; ++i)

-                    {

-                        int col = order[i];

-                        TreeColumn tc = tcs[col];

-                        c[i] = new Column(tc.getText());

-                        switch (tc.getAlignment()) {

-                            case SWT.RIGHT:

-                                c[i].aligning(Alignment.RIGHT);

-                                break;

-                            case SWT.CENTER:

-                                c[i].aligning(Alignment.CENTER);

-                                break;

-                            case SWT.LEFT:

-                                c[i].aligning(Alignment.LEFT);

-                                break;

-

-                        }

-                    }

-                    return c;

-                }

-

-                @Override

-                public Object getColumnValue(Object row, int columnIndex)

-                {

-                    return ((TreeItem)row).getText(ct.getColumnOrder()[columnIndex]);

-                }

-

-                @Override

-                public IContextObject getContext(Object row)

-                {

-                    return null;

-                }

-

-                @Override

-                public ResultMetaData getResultMetaData()

-                {

-                    return null;

-                }

-

-                @Override

-                public List<?> getElements()

-                {

-                    ArrayList<TreeItem>ret = new ArrayList<TreeItem>();

-                    for (TreeItem ti : ct.getItems())

-                    {

-                        if (selset.contains(ti))

-                            ret.add(ti);

-                    }

-                    /*

-                     * Add the remaining selection items which do not

-                     * have a parent in the selection - these would be missed

-                     * as the parent would not be printed or expanded.

-                     */

-                    for (Item i : selection)

-                    {

-                        if (i instanceof TreeItem)

-                        {

-                            TreeItem ti = (TreeItem)i;

-                            TreeItem pi = ti.getParentItem();

-                            if (pi != null && !selset.contains(pi))

-                                ret.add(ti);

-                        }

-                    }

-                    return ret;

-                }

-

-                @Override

-                public boolean hasChildren(Object element)

-                {

-                    int ret = ((TreeItem)element).getItemCount();

-                    return ret > 0;

-                }

-

-                @Override

-                public List<?> getChildren(Object parent)

-                {

-                    ArrayList<TreeItem>ret = new ArrayList<TreeItem>();

-                    for (TreeItem ti : ((TreeItem)parent).getItems())

-                    {

-                        if (selset.contains(ti))

-                            ret.add(ti);

-                    }

-                    return ret;

-                }

-

-                @Override

-                public boolean isSelected(Object row)

-                {

-                    return selset.contains(row);

-                }

-

-                @Override

-                public boolean isExpanded(Object row)

-                {

-                    return ((TreeItem)row).getExpanded();

-                }

-

-            };

-            return t;

-        }

     }

+

+    protected IResultTable convert(Table ct)

+    {

+        IResultTable t = new IResultTable() {

+

+            @Override

+            public Column[] getColumns()

+            {

+                TableColumn tcs[] = ct.getColumns();

+                int order[] = ct.getColumnOrder();

+                Column c[] = new Column[order.length];

+                for (int i = 0; i < order.length; ++i)

+                {

+                    int col = order[i];

+                    TableColumn tc = tcs[col];

+                    c[i] = new Column(tc.getText());

+                    switch (tc.getAlignment()) {

+                        case SWT.RIGHT:

+                            c[i].aligning(Alignment.RIGHT);

+                            break;

+                        case SWT.CENTER:

+                            c[i].aligning(Alignment.CENTER);

+                            break;

+                        case SWT.LEFT:

+                            c[i].aligning(Alignment.LEFT);

+                            break;

+                    }

+                }

+                return c;

+            }

+

+            @Override

+            public Object getColumnValue(Object row, int columnIndex)

+            {

+                return ((TableItem)row).getText(ct.getColumnOrder()[columnIndex]);

+            }

+

+            @Override

+            public IContextObject getContext(Object row)

+            {

+                return null;

+            }

+

+            @Override

+            public ResultMetaData getResultMetaData()

+            {

+                return null;

+            }

+

+            @Override

+            public int getRowCount()

+            {

+                if (selection != null)

+                    return selection.length;

+                else

+                    return ct.getItemCount();

+            }

+

+            @Override

+            public Object getRow(int rowId)

+            {

+                if (selection != null)

+                    return selection[rowId];

+                else

+                    return ct.getItems()[rowId];

+            }

+

+        };

+        return t;

+    }

+

+    interface IRTS extends IResultTree, ISelectionProvider {};

+    protected IResultTree convert(Tree ct)

+    {

+        final Set<Item> selset = selection != null ? new HashSet<Item>(Arrays.asList(selection)) : Collections.<Item>emptySet();

+        IResultTree t = new IRTS() {

+

+            @Override

+            public Column[] getColumns()

+            {

+                TreeColumn tcs[] = ct.getColumns();

+                int order[] = ct.getColumnOrder();

+                Column c[] = new Column[tcs.length];

+                for (int i = 0; i < order.length; ++i)

+                {

+                    int col = order[i];

+                    TreeColumn tc = tcs[col];

+                    c[i] = new Column(tc.getText());

+                    switch (tc.getAlignment()) {

+                        case SWT.RIGHT:

+                            c[i].aligning(Alignment.RIGHT);

+                            break;

+                        case SWT.CENTER:

+                            c[i].aligning(Alignment.CENTER);

+                            break;

+                        case SWT.LEFT:

+                            c[i].aligning(Alignment.LEFT);

+                            break;

+

+                    }

+                }

+                return c;

+            }

+

+            @Override

+            public Object getColumnValue(Object row, int columnIndex)

+            {

+                TreeItem treeitem = (TreeItem)row;

+                int[] order = ct.getColumnOrder();

+                // Special case for navigator view or other tree without columns

+                if (order.length == 0 || columnIndex == -1)

+                    return treeitem.getText();

+                return treeitem.getText(order[columnIndex]);

+            }

+

+            @Override

+            public IContextObject getContext(Object row)

+            {

+                return null;

+            }

+

+            @Override

+            public ResultMetaData getResultMetaData()

+            {

+                return null;

+            }

+

+            @Override

+            public List<?> getElements()

+            {

+                if (selection == null)

+                    return Arrays.asList(ct.getItems());

+                ArrayList<TreeItem>ret = new ArrayList<TreeItem>();

+                /*

+                 * Add the selection items which do not

+                 * have a parent in the selection - these would be missed

+                 * as the parent would not be printed or expanded.

+                 */

+                for (Item i : selection)

+                {

+                    if (i instanceof TreeItem)

+                    {

+                        TreeItem ti = (TreeItem)i;

+                        TreeItem pi = ti.getParentItem();

+                        if (!selset.contains(pi))

+                            ret.add(ti);

+                    }

+                }

+                return ret;

+            }

+

+            @Override

+            public boolean hasChildren(Object element)

+            {

+                int ret = ((TreeItem)element).getItemCount();

+                return ret > 0;

+            }

+

+            @Override

+            public List<?> getChildren(Object parent)

+            {

+                if (selection == null)

+                    return Arrays.asList(((TreeItem)parent).getItems());

+                ArrayList<TreeItem>ret = new ArrayList<TreeItem>();

+                for (TreeItem ti : ((TreeItem)parent).getItems())

+                {

+                    if (selset.contains(ti))

+                        ret.add(ti);

+                }

+                return ret;

+            }

+

+            @Override

+            public boolean isSelected(Object row)

+            {

+                return selset.contains(row);

+            }

+

+            @Override

+            public boolean isExpanded(Object row)

+            {

+                return ((TreeItem)row).getExpanded();

+            }

+

+        };

+        return t;

+    }

+

     private static class ContextImpl implements IOutputter.Context

     {

         private File outputDir;

diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/PopupMenu.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/PopupMenu.java
index 53d010f..ad68b02 100644
--- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/PopupMenu.java
+++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/PopupMenu.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 2008, 2010 SAP AG.

+ * Copyright (c) 2008, 2021 SAP AG and IBM Corporation.

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

@@ -9,6 +9,7 @@
  *

  * Contributors:

  *    SAP AG - initial API and implementation

+ *    Andrew Johnson - image disposal

  *******************************************************************************/

 package org.eclipse.mat.ui.util;

 

@@ -20,6 +21,7 @@
 import org.eclipse.jface.action.IAction;

 import org.eclipse.jface.action.IStatusLineManager;

 import org.eclipse.jface.resource.ImageDescriptor;

+import org.eclipse.mat.ui.MemoryAnalyserPlugin;

 import org.eclipse.mat.ui.Messages;

 import org.eclipse.swt.SWT;

 import org.eclipse.swt.widgets.Control;

@@ -143,7 +145,7 @@
                 {

                     ImageDescriptor id = action.getImageDescriptor();

                     if (id != null)

-                        menuItem.setImage(id.createImage());

+                        menuItem.setImage(MemoryAnalyserPlugin.getDefault().getImage(id));

                 }

 

                 menuItem.setData(action);

@@ -177,7 +179,7 @@
                         menuItem.setText(popup.name + '\t' + acceleratorText);

 

                     if (imageDescriptor != null)

-                        menuItem.setImage(imageDescriptor.createImage());

+                        menuItem.setImage(MemoryAnalyserPlugin.getDefault().getImage(imageDescriptor));

                     menuItem.setMenu(subMenu);

                 }

             }

diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/QueryContextMenu.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/QueryContextMenu.java
index 88eef1b..66177c3 100644
--- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/QueryContextMenu.java
+++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/QueryContextMenu.java
@@ -791,24 +791,6 @@
         copySelectionAction.setImageDescriptor(MemoryAnalyserPlugin.getImageDescriptor(ISharedImages.COPY));

         copySelectionAction.setToolTipText(Messages.QueryContextMenu_CopySelectionToTheClipboard);

         menu.add(copySelectionAction);

-        Action copySelectionAction2 = new Action()

-        {

-            @Override

-            public String getText()

-            {

-                return Messages.QueryContextMenu_Selection;

-            }

-

-            @Override

-            public void run()

-            {

-                Copy.copyToClipboard2(control);

-            }

-

-        };

-        copySelectionAction2.setImageDescriptor(MemoryAnalyserPlugin.getImageDescriptor(ISharedImages.COPY));

-        copySelectionAction2.setToolTipText(Messages.QueryContextMenu_CopySelectionToTheClipboard);

-        menu.add(copySelectionAction2);

     }

 

     /**