2

This might be a stupid question, but I am really confused after Googling.

We have a very big Java EE application. Now when it's time to go to production, there are a number of performance related problems raised. I am trying to get to the bottom of a memory leak issue. When I was looking through JProfiler, I found some enum variables that will not be garbage collected.

Just an example:

The application has one session factory, which is a kind of map i.e. Map<SessionKey, Object>. When the user is logged in that map will fill up and it will be cleared when that user logs out.

But with JProfiler I encountered some strange behavior. It shows SessionKey memory allocation increasing with the number of logins. When I'm logged in for the first time it shows 106 difference and after the second login it shows 206 difference in JProfiler. So this means the difference is increasing and increases more frequently.

is it enum never eligible for garbage collection?

I could not get it that what is wrong in it. Or I understand wrong. Let me know for more detail.

public enum SessionKey{
    LOGGEDIN_USER, DOCUMENT_ID, LOGGEDIN_USER_POSTS, LOGGEDIN_USER_PRIVILEGE, NORM_ID, DOCUMENT_REF_NO,DOCUMENT_STATUS, DOCUMENT,APPLICANT_USER, 
    NORM, CLIENT_SESSION_EXPIRED,  
    GININJECTOR, SCHEDULE_ID, DOCUMENT_ENTITY_TYPE,SOURCE_DOCUMENT_ID, CONFIGURATION_LIST, LOGGEDIN_USER_ID, 
    SOURCE_NORM_ID, MASKING_PANEL, IS_ETOKEN, 
    LOGGEDIN_USER_PRIVILEGE_NAMES, LOGGEDIN_USER_PRIVILEGE_IDS, IPADDRESS, AUTO_COMPLETE_SCHEDULER,
    MESSAGES, DEFAULT_CERTIFICATE, DOCUMENT_FORM_MAP,DOCUMENT_FORM_FCM_MAP,DOCTYPELIST,ACCESS_RIGHT,LOGGEDIN_USER_DEFAULT_POST,LAST_LOGIN_DETAILS, DOC_STATUS_ENUM_MASTERS
    ,MODULE_RIGHT_ENUM_MASTERS,MODULE_RIGHT, LOGGEDIN_USER_DEFAULT_PORTAL,
    LOGGEDIN_USER_DEFAULT_POST_MAP,HISTORY_CLEAR,DOC_DETAILS_PORTAL,ORGANIZATION_ID, DOCUMENT_DETAILS_FROM_JSP,PORTAL_MAP,ORGANIZATION,
    CONFIGURATION_MAP, DEFAULT_SIGN_CERTIFICATE,SYSTEM_VERSION,
    IS_LOGGEDIN_IN_ORGANIZATION, SUPPLIER_PORTAL_BASED_ON_URL, SUPPLIER_ORGANIZATION_BASED_ON_URL, BEFORE_LOGIN, USER_LANGUAGE, SERVER_DATE_TIME,DOCUMENTTYPE_CONFIG_TABLE;
}

SessionFacory code:

public class SessionFactory {
    private static HashMap session;
    public static HashMap getClientSessionInstance() {
        if (session == null) {
            session = new HashMap();
        }
        return session;
    }

    public static Object getValue(SessionKey key) {
        return getClientSessionInstance().get(key);
    }

    public static void putValue(SessionKey key, Object value) {

        getClientSessionInstance().put(key, value);
    }

    public static void remove(SessionKey key) {
        getClientSessionInstance().remove(key);
    }

    public static void clear() {
        getClientSessionInstance().remove(SessionKey.LOGGEDIN_USER);
        getClientSessionInstance().remove(SessionKey.LOGGEDIN_USER_PRIVILEGE);
        getClientSessionInstance().remove(SessionKey.LOGGEDIN_USER_ID);
        getClientSessionInstance().remove(SessionKey.LOGGEDIN_USER_POSTS);
        getClientSessionInstance().remove(SessionKey.CONFIGURATION_LIST);
        getClientSessionInstance().remove(SessionKey.DOCUMENTTYPE_CONFIG_TABLE);
        getClientSessionInstance().remove(SessionKey.SERVER_DATE_TIME);
        getClientSessionInstance().remove(SessionKey.USER_LANGUAGE);
        getClientSessionInstance().remove(SessionKey.SUPPLIER_ORGANIZATION_BASED_ON_URL);
        getClientSessionInstance().remove(SessionKey.SUPPLIER_PORTAL_BASED_ON_URL);
        getClientSessionInstance().remove(SessionKey.IS_LOGGEDIN_IN_ORGANIZATION);
        getClientSessionInstance().remove(SessionKey.DEFAULT_SIGN_CERTIFICATE);
        getClientSessionInstance().remove(SessionKey.CONFIGURATION_MAP);
        getClientSessionInstance().remove(SessionKey.ORGANIZATION);
        getClientSessionInstance().remove(SessionKey.LOGGEDIN_USER_DEFAULT_PORTAL);

        getClientSessionInstance().remove(SessionKey.ACCESS_RIGHT);
        getClientSessionInstance().remove(SessionKey.DOC_STATUS_ENUM_MASTERS);
        getClientSessionInstance().remove(SessionKey.IS_ETOKEN);

        getClientSessionInstance().remove(SessionKey.ORGANIZATION_ID);

        getClientSessionInstance().remove(SessionKey.LAST_LOGIN_DETAILS);
        getClientSessionInstance().remove(SessionKey.LOGGEDIN_USER_DEFAULT_POST);
        getClientSessionInstance().remove(SessionKey.MODULE_RIGHT);
        getClientSessionInstance().remove(SessionKey.MASKING_PANEL);
        getClientSessionInstance().remove(SessionKey.GININJECTOR);
        getClientSessionInstance().remove(SessionKey.MODULE_RIGHT_ENUM_MASTERS);
        getClientSessionInstance().remove(SessionKey.LOGGEDIN_USER_DEFAULT_POST_MAP);


        clearDocumentSession();

    }

    public static void clearDocumentSession() {
        getClientSessionInstance().remove(SessionKey.DOCUMENT_ID);
        getClientSessionInstance().remove(SessionKey.DOCUMENT_REF_NO);
        getClientSessionInstance().remove(SessionKey.DOCUMENT_STATUS);
        getClientSessionInstance().remove(SessionKey.DOCUMENT);
        getClientSessionInstance().remove(SessionKey.APPLICANT_USER);
        getClientSessionInstance().remove(SessionKey.NORM);
        getClientSessionInstance().remove(SessionKey.NORM_ID);
        getClientSessionInstance().remove(SessionKey.SCHEDULE_ID);
        if(getClientSessionInstance().containsKey(SessionKey.SOURCE_DOCUMENT_ID))
            getClientSessionInstance().remove(SessionKey.SOURCE_DOCUMENT_ID);
        if(getClientSessionInstance().containsKey(SessionKey.SOURCE_NORM_ID))
            getClientSessionInstance().remove(SessionKey.SOURCE_NORM_ID);
    }

}
4

3 回答 3

4

枚举对象就像应用程序的静态变量。它们不是垃圾收集的。

于 2013-04-19T11:44:55.900 回答
1

枚举定义的条目是定义枚举的静态实例。

以更清晰的方式,Java 编译器生成与以下代码匹配的字节码:

public class SessionKey {
    public static final SessionKey LOGGEDIN_USER = new SessionKey();
    .....
}

所以,枚举的实例永远不会被垃圾收集器收集,因为是静态实例,而且你的枚举“SessionKey”的实例数量在你正在运行的虚拟机的整个生命周期中都不会改变,可能问题与枚举无关有时分析器只给出实例状态的样本。

要完成,只有一次可以卸载枚举实例,并且是当枚举的类加载器卸载枚举时;)像所有静态实例一样!

于 2013-04-19T12:11:01.310 回答
0

枚举不应该是你的问题。正如其他答案所解释的那样,它们只被实例化一次。或者你正在用类加载器做一些奇怪的事情?

问题可能来自您的会话 HashMap。由于它是静态的,并且您只能使用 getClientSessionInstance() 访问它,因此应用程序中应该只有一个(尽管它不是线程保存)。可能出现的一个问题是应用程序中的某个地方 getClientSessionInstance() 被调用,并且在地图中插入了一些东西。由于您的 HashMap 没有键入,任何内容都可以作为键插入,而您的 clear() 函数不会删除它。为什么不在 HashMap 上调用 clear()?我建议使用 EnumMap 或至少使用 HashMap 并将您的 getClientSessionInstance() 函数设为私有。

我感兴趣的事情:您不想为每个用户创建一个会话映射,还是在客户端 jvm 上运行?

于 2013-04-19T12:39:26.910 回答