UI not eligible for garbage collection until server shutdown or republish

When logging out of our CDI-based application, we redirect to a new URL (via the FormSender add-on) and then close our UI and session. Unfortunately, it does not appear that our UI becomes eligible for garbage collection until the application server is stopped. We “know” this because when we have implemented the finalize() method in several of our classes and forced a full garbage collection via our debuging tool after “logging out,” all the finalize() methods get called except for the one of our UI class. However when we stop the application server, the finalize() method for each UI that was initialized then gets called. What could be holding on to each UI class after we close it and its session? Is it something related to CDI or the application server’s bean manager, and if so, what?

Here is a snippet of our UI class:

@CDIUI(value="workspace")
public class ScoreUI extends UI implements WorkspaceServlet {
  private static final String REQUEST_PARAMETER_MAP = "rpm";
  
  @Inject
  private Workspace workspace;
  @Inject
  private WorkspaceListener workspaceListener;
  private String contextPath;


  @WebServlet(value = { "/workspace/*" } )
  @VaadinServletConfiguration(ui = ScoreUI.class)
  public static class ScoreWorkspaceServlet extends VaadinCDIServlet {
    @Override
    protected VaadinServletService createServletService(DeploymentConfiguration deploymentConfiguration)
        throws ServiceException {
      VaadinCDIServletService service = new VaadinCDIServletService(this, deploymentConfiguration) {
        @Override
        public void requestEnd(VaadinRequest request, VaadinResponse response, VaadinSession session) {
          super.requestEnd(request, response, session);
          if (session != null) {
            try {
              session.setAttribute(REQUEST_PARAMETER_MAP, request.getParameterMap());
            }
            catch (NullPointerException e) {
              e.printStackTrack();
            }
          }
        }
      };

      service.init();
      return service;
    }
  }


  @Override
  protected void init(VaadinRequest vaadinRequest) {
    contextPath = vaadinRequest.getContextPath();

    // initialize workspace
    workspace.init();
    workspace.setWorkspaceListener(workspaceListener);
    workspaceListener.init(workspace, this);
  }

  @Override
  public void detach() {
    workspaceListener.destroyWorkspace();  // calls methods with @Remove annotations for StateFul beans
    super.detach();
  }

  public void redirectToLoginPage(String message) {
    // build login page URL
    String redirectPath = contextPath + "/login";
    
    // redirect to login page - post message if provided
    FormSender sender = new FormSender();
    sender.setFormAction(redirectPath);
    sender.setFormMethod(Method.POST);
    sender.setFormTarget("_top");
    if (message != null) {
      sender.addValue("message", message);
    }
    sender.extend(this);
    sender.submit();
    
    // close the UI and session
    VaadinSession session = getSession();
    close();
    session.close();

    // we've also tried this:
    // workspace = null;
    // workspaceListener = null;
  }
.
.
.
}


Versions

Java 6
Java EE 6
​EJB 3.1
CDI 1.0
Vaadin 7.5.2
Vaadin CDI add-on 1.0.3