混淆相关的JVM中的枚举对象分配

时间:2013-04-19 11:38:35

标签: java

这可能是一个愚蠢的问题,但谷歌搜索后我真的很困惑。

我们有一个非常大的Java EE应用程序。现在是时候进入生产阶段,出现了许多与性能相关的问题。我试图找到内存泄漏问题的底部。当我查看JProfiler时,我发现了一些不会被垃圾收集的枚举变量。

只是一个例子:

该应用程序有一个会话工厂,这是一种地图,即Map<SessionKey, Object>。当用户登录时,该地图将填满,并且当该用户退出时将清除该地图。

但是使用JProfiler我遇到了一些奇怪的行为。它显示SessionKey内存分配随着登录次数的增加而增加。当我第一次登录时显示 106差异,第二次登录后,它在JProfiler中显示 206差异。所以这意味着差异正在增加并且更频繁地增加。

枚举是否永远不符合垃圾回收的条件?

我无法理解它的错误。或者我理解错了。让我知道更多细节。

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代码:

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);
    }

}

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:1)

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

以更清晰的方式,java编译器生成一个匹配代码的字节码,如:

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

所以,枚举的实例永远不会被垃圾收集器收集,因为它是静态实例,而且你的枚举“SessionKey”实例的数量永远不会在你运行的VM的所有生命周期中改变,可能问题是没有关系的对于枚举,有时轮廓器只提供实例状态的样本。

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

答案 2 :(得分:0)

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

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

让我感兴趣的东西:你不想为每个用户创建会话映射,还是在客户端jvm上运行?