You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by jt...@apache.org on 2021/03/16 20:35:41 UTC

[netbeans] branch master updated: Avoid displaying classloader fields when there is at most single classloader in the dump

This is an automated email from the ASF dual-hosted git repository.

jtulach pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new e2e6fb4  Avoid displaying classloader fields when there is at most single classloader in the dump
     new a299d76  Merge pull request #2809 from JaroslavTulach/jtulach/UnnecessaryClassLoaders
e2e6fb4 is described below

commit e2e6fb4be4534e0d79d89f90b64b66033000609f
Author: Jaroslav Tulach <ja...@apidesign.org>
AuthorDate: Fri Mar 12 20:50:16 2021 +0100

    Avoid displaying classloader fields when there is at most single classloader in the dump
---
 .../lib/profiler/heap/HeapSegmentTest.java         | 40 ++++++++++--
 .../org/netbeans/lib/profiler/heap/HeapUtils.java  |  3 +-
 profiler/profiler.heapwalker/nbproject/project.xml | 15 +++++
 .../profiler/heapwalk/ClassesController.java       |  2 +-
 .../profiler/heapwalk/FieldsBrowserController.java | 25 ++++---
 .../profiler/heapwalk/HeapFragmentWalker.java      | 20 ++++++
 .../profiler/heapwalk/InstancesController.java     |  3 +-
 .../profiler/heapwalk/InstancesListController.java |  5 ++
 .../profiler/heapwalk/OverviewController.java      | 14 +---
 .../heapwalk/model/AbstractHeapWalkerNode.java     |  6 +-
 .../profiler/heapwalk/model/BrowserUtils.java      |  4 +-
 .../profiler/heapwalk/model/HeapWalkerNode.java    |  2 +
 .../profiler/heapwalk/model/ObjectArrayNode.java   |  2 +-
 .../profiler/heapwalk/model/ObjectFieldNode.java   |  2 +-
 .../profiler/heapwalk/model/ObjectNode.java        | 15 ++++-
 .../heapwalk/model/PrimitiveArrayNode.java         |  2 +-
 .../heapwalk/ui/FieldsBrowserControllerUI.java     |  2 +-
 .../heapwalk/model/HeapWalkerNodeTest.java         | 76 ++++++++++++++++++++++
 18 files changed, 198 insertions(+), 40 deletions(-)

diff --git a/profiler/lib.profiler/test/unit/src/org/netbeans/lib/profiler/heap/HeapSegmentTest.java b/profiler/lib.profiler/test/unit/src/org/netbeans/lib/profiler/heap/HeapSegmentTest.java
index 6141829..e2c6f20 100644
--- a/profiler/lib.profiler/test/unit/src/org/netbeans/lib/profiler/heap/HeapSegmentTest.java
+++ b/profiler/lib.profiler/test/unit/src/org/netbeans/lib/profiler/heap/HeapSegmentTest.java
@@ -21,7 +21,10 @@ package org.netbeans.lib.profiler.heap;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
@@ -29,6 +32,7 @@ import java.util.List;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import org.junit.Test;
 import org.netbeans.lib.profiler.heap.HeapUtils.HprofGenerator;
 
@@ -37,16 +41,15 @@ public class HeapSegmentTest {
     public void singleObject() throws IOException {
         singleObject(false);
     }
-    
+
     @Test
     public void singleObjectMultipleSegments() throws IOException {
         singleObject(true);
     }
-    
+
     private static void singleObject(boolean flush) throws IOException {
         File mydump = File.createTempFile("mydump", ".hprof");
-        generateSingleObject(new FileOutputStream(mydump), flush);
-        Heap heap = HeapFactory.createHeap(mydump);
+        Heap heap = generateSampleDump(mydump, flush);
         List<JavaClass> allClasses = heap.getAllClasses();
         assertEquals(5, allClasses.size());
         assertEquals("java.lang.String", allClasses.get(0).getName());
@@ -77,13 +80,38 @@ public class HeapSegmentTest {
         assertFalse("It is not daemon", (Boolean) daemon);
     }
 
+    public static Heap generateSampleDump(File mydump) throws IOException {
+        return generateSampleDump(mydump, true);
+    }
+
+    public static Heap generateComplexDump(File mydump) throws IOException, URISyntaxException {
+        InputStream is = HeapUtils.class.getResourceAsStream("heap_dump.bin");
+        FileOutputStream out = new FileOutputStream(mydump);
+        byte[] arr = new byte[4096];
+        for (;;) {
+            int len = is.read(arr);
+            if (len == -1) {
+                break;
+            }
+            out.write(arr, 0, len);
+        }
+        is.close();
+        out.close();
+        return HeapFactory.createHeap(mydump);
+    }
+
+    static Heap generateSampleDump(File mydump, boolean flush) throws IOException {
+        generateSingleObject(new FileOutputStream(mydump), flush);
+        return HeapFactory.createHeap(mydump);
+    }
+
     private static void generateSingleObject(OutputStream os, boolean flush) throws IOException {
         try (HprofGenerator gen = new HprofGenerator(os)) {
             gen.writeHeapSegment(new SampleDumpMemory(), flush);
             gen.writeHeapSegment(new SampleDumpMemory2(), flush);
         }
     }
-    
+
     private static class SampleDumpMemory implements HprofGenerator.Generator<HprofGenerator.HeapSegment> {
         @Override
         public void generate(HprofGenerator.HeapSegment seg) throws IOException {
@@ -118,5 +146,5 @@ public class HeapSegmentTest {
             seg.dumpPrimitive(threadId);
         }
     }
-    
+
 }
diff --git a/profiler/lib.profiler/test/unit/src/org/netbeans/lib/profiler/heap/HeapUtils.java b/profiler/lib.profiler/test/unit/src/org/netbeans/lib/profiler/heap/HeapUtils.java
index 6f7a57c..115c99c 100644
--- a/profiler/lib.profiler/test/unit/src/org/netbeans/lib/profiler/heap/HeapUtils.java
+++ b/profiler/lib.profiler/test/unit/src/org/netbeans/lib/profiler/heap/HeapUtils.java
@@ -328,7 +328,6 @@ final class HeapUtils {
                         .dumpClass();
             }
             generator.generate(seg);
-            seg.close();
         }
 
         @Override
@@ -435,5 +434,5 @@ final class HeapUtils {
             return stringId;
         }
     }
-    
+
 }
diff --git a/profiler/profiler.heapwalker/nbproject/project.xml b/profiler/profiler.heapwalker/nbproject/project.xml
index b332570..c29a5f7 100644
--- a/profiler/profiler.heapwalker/nbproject/project.xml
+++ b/profiler/profiler.heapwalker/nbproject/project.xml
@@ -161,6 +161,21 @@
                     </run-dependency>
                 </dependency>
             </module-dependencies>
+            <test-dependencies>
+                <test-type>
+                    <name>unit</name>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
+                        <recursive/>
+                        <compile-dependency/>
+                    </test-dependency>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.lib.profiler</code-name-base>
+                        <compile-dependency/>
+                        <test/>
+                    </test-dependency>
+                </test-type>
+            </test-dependencies>
             <friend-packages>
                 <friend>com.sun.tools.visualvm.heapdump</friend>
                 <friend>com.sun.tools.visualvm.heapviewer</friend>
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/ClassesController.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/ClassesController.java
index 5d9ebcd..a4eb87e 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/ClassesController.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/ClassesController.java
@@ -78,7 +78,7 @@ public class ClassesController extends AbstractTopLevelController implements Fie
         this.heapFragmentWalker = heapFragmentWalker;
 
         classesListController = new ClassesListController(this);
-        staticFieldsBrowserController = new FieldsBrowserController(this, FieldsBrowserController.ROOT_CLASS);
+        staticFieldsBrowserController = new FieldsBrowserController(this, FieldsBrowserController.ROOT_CLASS, true);
     }
 
     //~ Methods ------------------------------------------------------------------------------------------------------------------
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/FieldsBrowserController.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/FieldsBrowserController.java
index 8529f91..272d490 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/FieldsBrowserController.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/FieldsBrowserController.java
@@ -42,6 +42,8 @@ import javax.swing.tree.TreePath;
     "FieldsBrowserController_NoneString=<none>"
 })
 public class FieldsBrowserController extends AbstractController {
+
+    private final boolean showClassLoaders;
     //~ Inner Interfaces ---------------------------------------------------------------------------------------------------------
 
     public static interface Handler {
@@ -136,11 +138,11 @@ public class FieldsBrowserController extends AbstractController {
         protected String computeValue() {
             return Bundle.FieldsBrowserController_NoneString();
         }
-        
+
         protected String computeSize() {
             return ""; // NOI18N
         }
-        
+
         protected String computeRetainedSize() {
             return ""; // NOI18N
         }
@@ -165,8 +167,13 @@ public class FieldsBrowserController extends AbstractController {
     //~ Constructors -------------------------------------------------------------------------------------------------------------
 
     public FieldsBrowserController(Handler instancesControllerHandler, int rootMode) {
+        this(instancesControllerHandler, rootMode, true);
+    }
+
+    public FieldsBrowserController(Handler instancesControllerHandler, int rootMode, boolean showClassLoaders) {
         this.instancesControllerHandler = instancesControllerHandler;
         this.rootMode = rootMode;
+        this.showClassLoaders = showClassLoaders;
     }
 
     //~ Methods ------------------------------------------------------------------------------------------------------------------
@@ -244,15 +251,15 @@ public class FieldsBrowserController extends AbstractController {
     protected AbstractButton createControllerPresenter() {
         return ((FieldsBrowserControllerUI) getPanel()).getPresenter();
     }
-    
+
     public List getExpandedPaths() {
         return ((FieldsBrowserControllerUI)getPanel()).getExpandedPaths();
     }
-    
+
     public TreePath getSelectedRow() {
         return ((FieldsBrowserControllerUI)getPanel()).getSelectedRow();
     }
-    
+
     public void restoreState(List expanded, TreePath selected) {
         ((FieldsBrowserControllerUI)getPanel()).restoreState(expanded, selected);
     }
@@ -263,10 +270,12 @@ public class FieldsBrowserController extends AbstractController {
     }
 
     private HeapWalkerNode getFields(final Instance instance) {
+        int fieldsMode = showClassLoaders ? HeapWalkerNode.MODE_FIELDS : HeapWalkerNode.MODE_FIELDS_NO_CLASSLOADER;
+
         return HeapWalkerNodeFactory.createRootInstanceNode(instance, "this",   // NOI18N
                 new Runnable() { public void run() { ((FieldsBrowserControllerUI) getPanel()).refreshView(); } },
                 new Runnable() { public void run() { getPanel().repaint(); } },
-                HeapWalkerNode.MODE_FIELDS, instancesControllerHandler.getHeapFragmentWalker().getHeapFragment());
+                fieldsMode, instancesControllerHandler.getHeapFragmentWalker().getHeapFragment());
     }
 
     private HeapWalkerNode getFields(final JavaClass javaClass) {
@@ -278,13 +287,13 @@ public class FieldsBrowserController extends AbstractController {
 
     private HeapWalkerNode getFilteredFields(HeapWalkerNode fields, String filterValue) {
         //    ArrayList filteredFields = new ArrayList();
-        //    
+        //
         //    Iterator fieldsIterator = fields.iterator();
         //    while (fieldsIterator.hasNext()) {
         //      FieldValue field = (FieldValue)fieldsIterator.next();
         //      if (matchesFilter(field)) filteredFields.add(field);
         //    }
-        //    
+        //
         //    return filteredFields;
         return fields;
     }
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/HeapFragmentWalker.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/HeapFragmentWalker.java
index 55cf36b..4033479 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/HeapFragmentWalker.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/HeapFragmentWalker.java
@@ -23,6 +23,7 @@ import org.netbeans.lib.profiler.heap.*;
 import org.netbeans.modules.profiler.heapwalk.ui.HeapFragmentWalkerUI;
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
@@ -318,6 +319,25 @@ public class HeapFragmentWalker {
         return null;
     }
 
+    private Integer classLoaderCount;
+    public final int countClassLoaders() {
+        if (this.classLoaderCount != null) {
+            return this.classLoaderCount;
+        }
+        int nclassloaders = 0;
+        JavaClass cl = heapFragment.getJavaClassByName("java.lang.ClassLoader"); // NOI18N
+        if (cl != null) {
+            nclassloaders = cl.getInstancesCount();
+
+            Collection<JavaClass> jcs = cl.getSubClasses();
+
+            for (JavaClass jc : jcs) {
+                nclassloaders += jc.getInstancesCount();
+            }
+        }
+        return this.classLoaderCount = nclassloaders;
+    }
+
 
     public static interface StateListener {
 
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/InstancesController.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/InstancesController.java
index 4a71cd7..1f8f886 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/InstancesController.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/InstancesController.java
@@ -98,7 +98,8 @@ public class InstancesController extends AbstractTopLevelController implements F
             public void refresh() { setJavaClass(selectedClass); }
         };
         instancesListController = new InstancesListController(this);
-        fieldsBrowserController = new FieldsBrowserController(this, FieldsBrowserController.ROOT_INSTANCE);
+        boolean showClassLoaders = heapFragmentWalker.countClassLoaders() > 1;
+        fieldsBrowserController = new FieldsBrowserController(this, FieldsBrowserController.ROOT_INSTANCE, showClassLoaders);
         referencesBrowserController = new ReferencesBrowserController(this);
 
         classPresenter.setHeapFragmentWalker(heapFragmentWalker);
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/InstancesListController.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/InstancesListController.java
index 83bab97..0ee6811 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/InstancesListController.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/InstancesListController.java
@@ -487,6 +487,11 @@ public class InstancesListController extends AbstractController {
             return 0;
         }
 
+        @Override
+        public boolean isModeFields() {
+            return false;
+        }
+
         public int getNChildren() {
             return 0;
         }
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/OverviewController.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/OverviewController.java
index 25c60dd..cf5d924 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/OverviewController.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/OverviewController.java
@@ -137,21 +137,11 @@ public class OverviewController extends AbstractController {
         Heap heap = heapFragmentWalker.getHeapFragment();
         HeapSummary hsummary = heap.getSummary();
         long finalizers = computeFinalizers(heap);
-        int nclassloaders = 0;
-        JavaClass cl = heap.getJavaClassByName("java.lang.ClassLoader"); // NOI18N
         NumberFormat numberFormat = (NumberFormat)NumberFormat.getInstance().clone();
         numberFormat.setMaximumFractionDigits(1);
         
         oome = getOOMEThread(heap);
-        if (cl != null) {
-            nclassloaders = cl.getInstancesCount();
-            
-            Collection<JavaClass> jcs = cl.getSubClasses();
-            
-            for (JavaClass jc : jcs) {
-                nclassloaders += jc.getInstancesCount();
-            }
-        }
+        int nclassloaders = heapFragmentWalker.countClassLoaders();
         
         String filename = LINE_PREFIX
                 + Bundle.OverviewController_FileItemString(
@@ -202,7 +192,7 @@ public class OverviewController extends AbstractController {
                 + Bundle.OverviewController_SummaryString() + "</b><br><hr>" + dateTaken + "<br>" + filename + "<br>" + filesize + "<br><br>" + liveBytes // NOI18N
                 + "<br>" + liveClasses + "<br>" + liveInstances + "<br>" + classloaders + "<br>" + gcroots + "<br>" + finalizersInfo + oomeString; // NOI18N
     }
-    
+
     public String computeEnvironment() {
         String sysinfoRes = Icons.getResource(HeapWalkerIcons.SYSTEM_INFO);
         String header =  "<b><img border='0' align='bottom' src='nbresloc:/" + sysinfoRes + "'>&nbsp;&nbsp;" // NOI18N
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/AbstractHeapWalkerNode.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/AbstractHeapWalkerNode.java
index 6da91ac..6557f09 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/AbstractHeapWalkerNode.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/AbstractHeapWalkerNode.java
@@ -41,7 +41,7 @@ public abstract class AbstractHeapWalkerNode extends HeapWalkerNode {
     private String size;
     private String retainedSize;
     private HeapWalkerNode[] children;
-    private int mode = HeapWalkerNode.MODE_FIELDS;
+    private final int mode;
 
     private Map<Object, Integer> indexes;
 
@@ -107,6 +107,10 @@ public abstract class AbstractHeapWalkerNode extends HeapWalkerNode {
         return getNChildren() == 0;
     }
 
+    public final boolean isModeFields() {
+        return mode != MODE_REFERENCES;
+    }
+
     public int getMode() {
         return mode;
     }
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/BrowserUtils.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/BrowserUtils.java
index e04c042..6bdf519 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/BrowserUtils.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/BrowserUtils.java
@@ -307,13 +307,13 @@ public class BrowserUtils {
     }
     
     private static String pathFromRoot(TreePath path) {
-        int m = ((HeapWalkerNode)path.getLastPathComponent()).getMode();
+        final HeapWalkerNode last = (HeapWalkerNode)path.getLastPathComponent();
         Object[] nodes = path.getPath();
         StringBuilder b = new StringBuilder();
         int s = nodes.length;
         for (int i = 0; i < s; i++) {
             HeapWalkerNode n = (HeapWalkerNode)nodes[i];
-            if (m == HeapWalkerNode.MODE_FIELDS) fieldFromRoot(n, b, i, s);
+            if (last.isModeFields()) fieldFromRoot(n, b, i, s);
             else referenceFromRoot(n, b, i, s);
             b.append("\n"); // NOI18N
         }
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/HeapWalkerNode.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/HeapWalkerNode.java
index d8624a7..aacf326 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/HeapWalkerNode.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/HeapWalkerNode.java
@@ -38,6 +38,7 @@ public abstract class HeapWalkerNode extends CCTNode {
 
     public static final int MODE_FIELDS = 1;
     public static final int MODE_REFERENCES = 2;
+    public static final int MODE_FIELDS_NO_CLASSLOADER = 3;
 
     //~ Methods ------------------------------------------------------------------------------------------------------------------
 
@@ -83,6 +84,7 @@ public abstract class HeapWalkerNode extends CCTNode {
      * There are two different algorithms for generating childs in both Browsers.
      */
     public abstract int getMode();
+    public abstract boolean isModeFields();
     
     
     public static TreePath fromNode(TreeNode node) {
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectArrayNode.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectArrayNode.java
index 874b226..171ee45 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectArrayNode.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectArrayNode.java
@@ -127,7 +127,7 @@ public class ObjectArrayNode extends ArrayNode {
             public HeapWalkerNode[] computeChildren() {
                 HeapWalkerNode[] children = null;
 
-                if (getMode() == HeapWalkerNode.MODE_FIELDS) {
+                if (isModeFields()) {
                     int fieldsSize = getInstance().getLength();
 
                     if (fieldsSize == 0) {
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectFieldNode.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectFieldNode.java
index f36425b..665f163 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectFieldNode.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectFieldNode.java
@@ -40,7 +40,7 @@ public class ObjectFieldNode extends ObjectNode implements HeapWalkerFieldNode {
     }
 
     public ObjectFieldNode(ObjectFieldValue fieldValue, HeapWalkerNode parent, int mode) {
-        super((mode == HeapWalkerNode.MODE_FIELDS) ? fieldValue.getInstance() : fieldValue.getDefiningInstance(),
+        super((mode != HeapWalkerNode.MODE_REFERENCES) ? fieldValue.getInstance() : fieldValue.getDefiningInstance(),
               fieldValue.getField().getName(), parent, mode);
         this.fieldValue = fieldValue;
 
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectNode.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectNode.java
index 3be984a..a2c17a6 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectNode.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/ObjectNode.java
@@ -24,6 +24,7 @@ import org.openide.util.NbBundle;
 import java.util.ArrayList;
 import javax.swing.Icon;
 import javax.swing.ImageIcon;
+import org.netbeans.lib.profiler.heap.Field;
 import org.netbeans.lib.profiler.heap.FieldValue;
 import org.netbeans.lib.profiler.heap.GCRoot;
 import org.netbeans.lib.profiler.heap.Instance;
@@ -141,13 +142,21 @@ public class ObjectNode extends InstanceNode {
             public HeapWalkerNode[] computeChildren() {
                 HeapWalkerNode[] children = null;
 
-                if (getMode() == HeapWalkerNode.MODE_FIELDS) {
+                if (isModeFields()) {
                     if (hasInstance()) {
                         ArrayList fieldValues = new ArrayList();
                         fieldValues.addAll(getInstance().getFieldValues());
-                        fieldValues.addAll(getInstance().getStaticFieldValues());
+                        final boolean skipClassLoaders = getMode() == HeapWalkerNode.MODE_FIELDS_NO_CLASSLOADER;
+                        for (Object v : getInstance().getStaticFieldValues()) {
+                            FieldValue fv = (FieldValue) v;
+                            final Field field = fv.getField();
+                            if (skipClassLoaders && field.isStatic() && "<classLoader>".equals(field.getName())) { // NOI18N
+                                continue;
+                            }
+                            fieldValues.add(v);
+                        }
 
-                        if (fieldValues.size() == 0) {
+                        if (fieldValues.isEmpty()) {
                             // Instance has no fields
                             children = new HeapWalkerNode[1];
                             children[0] = HeapWalkerNodeFactory.createNoFieldsNode(ObjectNode.this);
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/PrimitiveArrayNode.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/PrimitiveArrayNode.java
index bdc653a..58b1afc 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/PrimitiveArrayNode.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/model/PrimitiveArrayNode.java
@@ -128,7 +128,7 @@ public class PrimitiveArrayNode extends ArrayNode {
             public HeapWalkerNode[] computeChildren() {
                 HeapWalkerNode[] children = null;
 
-                if (getMode() == HeapWalkerNode.MODE_FIELDS) {
+                if (isModeFields()) {
                     int fieldsSize = getInstance().getLength();
 
                     if (fieldsSize == 0) {
diff --git a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/ui/FieldsBrowserControllerUI.java b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/ui/FieldsBrowserControllerUI.java
index 64247ad..3c90101 100644
--- a/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/ui/FieldsBrowserControllerUI.java
+++ b/profiler/profiler.heapwalker/src/org/netbeans/modules/profiler/heapwalk/ui/FieldsBrowserControllerUI.java
@@ -153,7 +153,7 @@ public class FieldsBrowserControllerUI extends JTitledPanel {
         }
 
         public void mouseClicked(MouseEvent e) {
-            if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
+             if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
                 int row = fieldsListTable.rowAtPoint(e.getPoint());
                 if (e.getX() >= fieldsListTable.getTree().getRowBounds(row).x -
                                 fieldsListTable.getTreeCellOffsetX() && row != -1) {
diff --git a/profiler/profiler.heapwalker/test/unit/src/org/netbeans/modules/profiler/heapwalk/model/HeapWalkerNodeTest.java b/profiler/profiler.heapwalker/test/unit/src/org/netbeans/modules/profiler/heapwalk/model/HeapWalkerNodeTest.java
new file mode 100644
index 0000000..d967787
--- /dev/null
+++ b/profiler/profiler.heapwalker/test/unit/src/org/netbeans/modules/profiler/heapwalk/model/HeapWalkerNodeTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.profiler.heapwalk.model;
+
+import java.io.File;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.lib.profiler.heap.Heap;
+import org.netbeans.lib.profiler.heap.HeapSegmentTest;
+import org.netbeans.modules.profiler.heapwalk.HeapFragmentWalker;
+
+public class HeapWalkerNodeTest extends NbTestCase {
+
+    public HeapWalkerNodeTest(String n) {
+        super(n);
+    }
+
+    private static void assertChildMode(ObjectNode on) {
+        ObjectNode ch = new ObjectNode(null, "any", on);
+        assertEquals("Same mode on child", on.getMode(), ch.getMode());
+    }
+
+    public void testModeFields1() {
+        ObjectNode on = new ObjectNode(null, "any", null, HeapWalkerNode.MODE_FIELDS);
+        assertTrue("Showing fields", on.isModeFields());
+        assertChildMode(on);
+    }
+
+
+    public void testModeFields2() {
+        ObjectNode on = new ObjectNode(null, "any", null, HeapWalkerNode.MODE_FIELDS_NO_CLASSLOADER);
+        assertTrue("Showing fields", on.isModeFields());
+        assertChildMode(on);
+    }
+
+    public void testModeFields3() {
+        ObjectNode on = new ObjectNode(null, "any", null, HeapWalkerNode.MODE_REFERENCES);
+        assertFalse("Not showing fields", on.isModeFields());
+        assertChildMode(on);
+    }
+
+    public void testSimpleHeapDumpAnalysis() throws Exception {
+        clearWorkDir();
+        File mydump = new File(getWorkDir(), "sample.hprof");
+        mydump.getParentFile().mkdirs();
+        Heap heap = HeapSegmentTest.generateSampleDump(mydump);
+
+        HeapFragmentWalker walker = new HeapFragmentWalker(heap, null);
+        assertEquals("No classloaders", 0, walker.countClassLoaders());
+    }
+
+    public void testComplexHeapDumpAnalysis() throws Exception {
+        clearWorkDir();
+        File mydump = new File(getWorkDir(), "complex.hprof");
+        mydump.getParentFile().mkdirs();
+        Heap heap = HeapSegmentTest.generateComplexDump(mydump);
+
+        HeapFragmentWalker walker = new HeapFragmentWalker(heap, null);
+        assertEquals("Heap dump uses some classloaders", 2, walker.countClassLoaders());
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists