@Override
  protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e) {
    DebugProcessImpl debugProcess = JavaDebugProcess.getCurrentDebugProcess(e);
    ObjectReference reference = getObjectReference(node);
    if (debugProcess == null || reference == null) return;

    XDebuggerTree tree = node.getTree();
    RetainedSizeDialog dialog = new RetainedSizeDialog(tree.getProject(), tree.getEditorsProvider(), tree.getSourcePosition(),
                                                       nodeName, node.getValueContainer(), tree.getValueMarkers(),
                                                       DebuggerUIUtil.getSession(e),
                                                       true);
    dialog.show();

    SuspendContextImpl suspendContext = debugProcess.getSuspendManager().getPausedContext();
    debugProcess.getManagerThread().schedule(new SuspendContextCommandImpl(suspendContext) {
      @Override
      public void contextAction(@NotNull SuspendContextImpl suspendContext) {
        try {
          if (dialog.isDisposed()) {
            return;
          }

          EvaluationContextImpl evaluationContext = new EvaluationContextImpl(suspendContext, suspendContext.getFrameProxy());
          MemoryAgent memoryAgent = MemoryAgent.get(evaluationContext);
          if (memoryAgent.isDisabled()) {
            dialog.setAgentCouldntBeLoadedMessage();
            return;
          }

          Disposer.register(dialog.getDisposable(), () -> memoryAgent.cancelAction());
          memoryAgent.setProgressIndicator(dialog.createProgressIndicator());
          MemoryAgentActionResult<Pair<long[], ObjectReference[]>> result = memoryAgent.estimateObjectSize(
            evaluationContext, reference, Registry.get("debugger.memory.agent.action.timeout").asInteger()
          );

          if (dialog.isDisposed()) {
            return;
          }

          interpretResult(result, dialog);
        }
        catch (EvaluateException e) {
          XDebuggerManagerImpl.getNotificationGroup().createNotification(JavaDebuggerBundle.message("action.failed"), NotificationType.ERROR);
        }
      }

      private static void interpretResult(@NotNull MemoryAgentActionResult<Pair<long[], ObjectReference[]>> result,
                                          @NotNull RetainedSizeDialog dialog) {
        if (result.executedSuccessfully()) {
          Pair<long[], ObjectReference[]> sizesAndHeldObjects = result.getResult();
          long[] sizes = sizesAndHeldObjects.getFirst();
          dialog.setHeldObjectsAndSizes(
            Arrays.asList(sizesAndHeldObjects.getSecond()),
            sizes[0],
            sizes[1]
          );
        }
        else {
          dialog.setCalculationTimeoutMessage();
        }
      }

      @Override
      public void commandCancelled() {
        LOG.info("command cancelled");
      }
    });
  }
@Override
  protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e)