1

我们正在使用自定义 Java Beans 的 Domino 8.5.2 上构建 xPages 应用程序,并且开发服务器有时会遇到 java/lang/OutOfMemoryError。重新启动http任务后一切正常,但是如果它发生在客户的服务器上,这当然是一个绝对的杀手。因此,我查看了 Eclipse 内存分析中的堆转储,并检查了我得到的顶级消费者:

截图 1

显然,BCCPropertyStore 类经常被实例化,以至于它占整个堆的 20%,尽管它应该是单例的。课程是这样开始的:

public class BCCPropertyStore {

// Constants
private static final String     CLASS_NAME  = "BCCPropertySynch ";
private static BCCPropertyStore instance    = new BCCPropertyStore();

...

public static BCCPropertyStore getInstance() {
    return instance;
}

每次使用它时,我们都用 BCCPropertyStore.getInstance() 调用它,它是静态的,所以我的理解是它不应该有多个实例(Java bean 通常在应用程序范围内,所以我不明白为什么他们也应该有多个实例)。但是,如果我查看重复的类,就会发现还有很多 xPages-classes 出现的频率比它们应该出现的要多得多:

截图 2

没有成千上万的用户登录到应用程序,所有这些实例都可以为其创建,只有我和一位开发人员。HTTPJVMMaxHeapSize 设置为 256M,理论上这对于一个应用程序的大小应该绰绰有余。

为什么 JVM 会创建这么多无用的类实例,直到内存耗尽,为什么它们没有被垃圾收集器清除?这是特定于 xPages 的问题还是我错过了什么?

更新

今天错误再次发生,我并不聪明。我按照下面的建议将 BCCPropertyStore 更改为枚举,显然这并没有改变任何东西,因为堆转储看起来与我之前发布的屏幕截图中的几乎相同。

是否有任何工具可以在 JVM 运行时监控它的内存使用情况,或者类似的工具可以帮助我们确定修复和建议是否有效?

这是堆栈跟踪:

2013-05-07T10:44:32.441+02:00 java.lang.RuntimeException: com.ibm.xsp.FacesExceptionEx: java.lang.OutOfMemoryError at com.ibm.designer.runtime.domino.adapter.ComponentModule.initModule(ComponentModule .java:433) 在 com.ibm.domino.xsp.module.nsf.NSFComponentModule.initModule(NSFComponentModule.java:427) 在 com.ibm.domino.xsp.module.nsf.NSFService.loadModule(NSFService.java:561 ) 在 com.ibm.domino.xsp.module.nsf.NSFService.doService(NSFService.java:342) 在 com.ibm.domino.xsp.module.nsf.NSFService.doServiceInternal(NSFService.java:521) 在 com。 ibm.designer.runtime.domino.adapter.LCDEnvironment.doService(LCDEnvironment.java:304) 在 com.ibm.designer.runtime.domino.adapter.LCDEnvironment.service(LCDEnvironment.java:261) 在 com.ibm.domino。 xsp.bridge.http.engine.XspCmdManager.service(XspCmdManager.java:291) 原因:com.ibm.xsp.FacesExceptionEx:com.ibm.xsp.config.CLBootStrap.initContext(CLBootStrap.java:73) 处的 java.lang.OutOfMemoryError com.ibm.xsp.config.BootStrap.init(BootStrap.java:60) ) at com.ibm.xsp.config.ConfigureCoreListener.contextInitialized(ConfigureCoreListener.java:58) at com.ibm.designer.runtime.domino.adapter.ComponentModule.initModule(ComponentModule.java:425) ... 7 更多: java.util.Hashtable.newEntry(Hashtable.java:91) 处的 java.lang.OutOfMemoryError 在 java.util.PropertyPermissionCollection.add(PropertyPermissionCollection.java:40) 处的 java.util.Hashtable.put(Hashtable.java:766) ) 在 java.security.Permissions.add(Permissions.java:98) 在 org.apache.harmony.security.fortress.PolicyUtils.toPermissionCollection(PolicyUtils.java:541) 在 org.apache.harmony.security.fortress.DefaultPolicy。getPermissions(DefaultPolicy.java:242) at org.apache.harmony.security.fortress.DefaultPolicy.implies(DefaultPolicy.java:365) at java.security.ProtectionDomain.implies(ProtectionDomain.java:159) at java.security.AccessController .checkPermission(AccessController.java:98) at java.lang.SecurityManager.checkPermission(SecurityManager.java:533) at org.eclipse.osgi.framework.internal.core.Framework.checkAdminPermission(Framework.java:1299) at org. eclipse.osgi.framework.internal.core.BundleHost.getResource(BundleHost.java:266) 在 com.ibm.domino.xsp.module.nsf.Activator.findResource(Activator.java:84) 在 com.ibm.domino。 xsp.module.nsf.Activator.findResource(Activator.java:103) 在 com.ibm.domino.xsp.module.nsf.Activator.findResource(Activator.java:103) 在 com.ibm.domino.xsp.module。 nsf.Activator.findResource(激活器。java:67) 在 com.ibm.domino.xsp.module.nsf.NotesClientClassLoader.getResource(NotesClientClassLoader.java:130) 在 java.lang.ClassLoader.getResource(ClassLoader.java:438) 在 com.ibm.domino.xsp .module.nsf.ModuleClassLoader.getResource(ModuleClassLoader.java:117) 在 java.lang.ClassLoader.getResourceAsStream(ClassLoader.java:503) 在 javax.xml.parsers.SecuritySupport$4.run(Unknown Source) 在 java.security。 AccessController.doPrivileged(AccessController.java:202) 在 javax.xml.parsers.FactoryFinder.findJarServiceProvider(Unknown Source) 在 javax.xml.parsers.FactoryFinder.find(Unknown) 在 javax.xml.parsers.SecuritySupport.getResourceAsStream(Unknown Source)来源)在 javax.xml.parsers.SAXParserFactory.newInstance(Unknown Source) 在 org.apache.commons.digester.Digester.getFactory(Digester.java:512) 在 org.apache.commons.digester.Digester.getParser(Digester.java:686) 在 org.apache.commons.digester.Digester.getXMLReader(Digester.java:902) 在 org.apache.commons.digester.Digester.parse(Digester. java:1548) 在 com.sun.faces.config.ConfigureListener.parse(ConfigureListener.java:1229) 在 com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:328) 在 com.ibm.xsp.config .CLBootStrap.initContext(CLBootStrap.java:65) ... 10 更多 2013-05-07T10:44:33.879+02:00 java.lang.OutOfMemoryError 在 java.util.HashMap.newElementArray(HashMap.java:282) 在java.util.HashMap.rehash(HashMap.java:686) 在 java.util.HashMap.rehash(HashMap.java:730) 在 java.util.HashMap.putImpl(HashMap.java:611) 在 java.util.HashMap .put(HashMap.java:605) 在 com.ibm.domino.xsp.module.nsf.RuntimeFileSystem。在 com.ibm.domino.xsp.module.nsf.NSFComponentModule.initNSFData(NSFComponentModule.java:565) 上刷新(RuntimeFileSystem.java:269) 在 com.ibm.domino.xsp.module.nsf.NSFComponentModule.doInitModule(NSFComponentModule. java:439) 在 com.ibm.designer.runtime.domino.adapter.ComponentModule.initModule(ComponentModule.java:412) 在 com.ibm.domino.xsp.module.nsf.NSFComponentModule.initModule(NSFComponentModule.java:427)在 com.ibm.domino.xsp.module.nsf.NSFService.loadModule(NSFService.java:561) 在 com.ibm.domino.xsp.module.nsf.NSFService.doServiceInternal(NSFService.java:439) 在 com.ibm .domino.xsp.module.nsf.NSFService.doService(NSFService.java:342) 在 com.ibm.designer.runtime.domino.adapter.LCDEnvironment.doService(LCDEnvironment.java:304) 在 com.ibm.designer.runtime .domino.adapter.LCDEnvironment.service(LCDEnvironment.java:261) 在 com.ibm.domino.xsp.bridge.http.engine.XspCmdManager.service(XspCmdManager.java:291) 2013-05-07T10:46:17.582+02:00 java.util.OutOfMemoryError。 HashMap.newElementArray(HashMap.java:282) 在 java.util.HashMap.rehash(HashMap.java:686) 在 java.util.HashMap.rehash(HashMap.java:730) 在 java.util.HashMap.putImpl(HashMap .java:611) 在 java.util.HashMap.put(HashMap.java:605) 在 com.ibm.domino.xsp.module.nsf.RuntimeFileSystem.refresh(RuntimeFileSystem.java:269) 在 com.ibm.domino。 xsp.module.nsf.NSFComponentModule.initNSFData(NSFComponentModule.java:565) 在 com.ibm.domino.xsp.module.nsf.NSFComponentModule.doInitModule(NSFComponentModule.java:439) 在 com.ibm.designer.runtime.domino。 com.ibm.domino.xsp.module.nsf.NSFComponentModule 上的 adapter.ComponentModule.initModule(ComponentModule.java:412)。initModule(NSFComponentModule.java:427) 在 com.ibm.domino.xsp.module.nsf.NSFService.loadModule(NSFService.java:561) 在 com.ibm.domino.xsp.module.nsf.NSFService.doServiceInternal(NSFService. java:439) 在 com.ibm.domino.xsp.module.nsf.NSFService.doService(NSFService.java:342) 在 com.ibm.designer.runtime.domino.adapter.LCDEnvironment.doService(LCDEnvironment.java:304)在 com.ibm.designer.runtime.domino.adapter.LCDEnvironment.service(LCDEnvironment.java:261) 在 com.ibm.domino.xsp.bridge.http.engine.XspCmdManager.service(XspCmdManager.java:291)342) 在 com.ibm.designer.runtime.domino.adapter.LCDEnvironment.doService(LCDEnvironment.java:304) 在 com.ibm.designer.runtime.domino.adapter.LCDEnvironment.service(LCDEnvironment.java:261) 在 com .ibm.domino.xsp.bridge.http.engine.XspCmdManager.service(XspCmdManager.java:291)342) 在 com.ibm.designer.runtime.domino.adapter.LCDEnvironment.doService(LCDEnvironment.java:304) 在 com.ibm.designer.runtime.domino.adapter.LCDEnvironment.service(LCDEnvironment.java:261) 在 com .ibm.domino.xsp.bridge.http.engine.XspCmdManager.service(XspCmdManager.java:291) 

4

4 回答 4

1

这是一个长镜头,但我听说许多 Java 企业服务器存在与类加载器、静态对象和应用程序重新部署相关的内存泄漏问题。

您是否可以通过重复清理/运行应用程序周期来检查是否可以重新创建 java/lang/OutOfMemoryError?

为了减少这个问题您可以尝试将静态对象移动到应用程序范围。

于 2013-04-26T13:16:14.160 回答
0

为什么 JVM 会创建这么多无用的类实例,直到内存耗尽?

它绝不能认为它们是无用的。

为什么它们没有被垃圾收集器消灭?

因为某些东西仍然带有对它们的引用。由于该类带有它自己的静态引用,我怀疑就是这样。

这是特定于 xPages 的问题还是我错过了什么?

此处提供的代码不足以确定原因,因为我们看不到 BCCPropertyStore 的构造函数。此外,我们不知道除了使这个类成为单例之外,您是否还把它放在一个可能导致它被序列化的范围内。

我要提供的第一个建议是切换到枚举模式来定义单例。

public enum BCCPropertyStore {
  INSTANCE;

  public static BCCPropertyStore getInstance() {
    return INSTANCE;
  }
}
于 2013-04-26T12:56:44.203 回答
0

是否有理由不使用托管 bean 而不是非托管 bean?如果您有一个作用域为应用程序的托管 bean,您仍然可以使用 ExtLibUtil.resolveVariable() 从 Java 访问它。这样它只会创建一个实例,JVM(特定于 NSF)将在需要时创建它,并在卸载时为您删除它。因此,您不需要对自身内部的类进行静态引用。

如果您没有扩展库,那么查看代码将为您提供静态方法所需的内容。

于 2013-04-26T13:29:02.690 回答
0

除了上面 Nathan 的评论之外......您还应该使用磁盘持久性(即:将页面保存到磁盘)而不是重量级自定义 Java 对象的内存选项 - 如果需要高端可伸缩性,这一点尤其重要。这样做时,请确保您的 bean 及其成员相应地是可序列化的和/或瞬态的。这种方法将从根本上减少堆空间的使用——磁盘空间也比 RAM 便宜!

于 2013-04-30T20:35:17.903 回答