这可能是一个愚蠢的问题,但谷歌搜索后我真的很困惑。
我们有一个非常大的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);
}
}
答案 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上运行?