分析 Java 中 OutOfMemoryError 的堆转储
我的 Java 程序不断出现 OutOfMemoryError
,我相信某处存在内存泄漏。在研究这个问题时,多个站点建议使用 Eclipse Memory Analyzer 工具,因此我在命令中添加了 -XX:+HeapDumpOnOutOfMemoryError
标志,以便在下次发生错误时获取堆转储。检查转储后,占用最多空间的对象是“17,481 个“com.couchbase.client.core.deps.org.LatencyUtils.LatencyStats”实例,由“org.springframework.boot.loader.LaunchedURLClassLoader @ 0x6c7c24510”加载。占用 1,978,652,856 (59.03%) 字节。”
我认为这是记录器打印了太多日志,因为 Java Couchbase 代码打印了大量日志在 INFO
级别,所以我尝试将日志级别设置为WARN
但尝试后,结果相同。希望有任何见解或建议,谢谢。
编辑:调用 Couchbase 的代码的某些部分:
@Autowired
private CouchbaseConfig couchbaseConfig;
public List<ArLedger> getBranchArLedgers(String branchId, String fromDate, String toDate) {
String query = Queries.GET_AR_LEDGER_BY_BRANCH_AND_DATE_RANGE;
query = MessageFormat.format(query, branchId, fromDate, toDate);
Cluster cluster = null;
try {
cluster = couchbaseConfig.connectToCouchbase();
QueryResult queryResult = cluster.query(query);
return queryResult.rowsAs(ArLedger.class);
} catch (Exception e) {
e.printStackTrace();
return Collections.emptyList();
} finally {
if (cluster != null) {
cluster.disconnect();
}
}
}
以及注入的 CouchbaseConfig 中的 connectToCouchbase():
@Value("${app.couchbase.connection-string}")
private String connectionString;
@Value("${app.couchbase.username}")
private String username;
@Value("${app.couchbase.password}")
private String password;
public Cluster connectToCouchbase() {
return Cluster.connect(connectionString, username, password);
}
编辑 2:更新了代码以遵循 dnault 的建议,以及运行代码时发生的错误的屏幕截图:
CouchbaseConfig:
@Configuration
public class CouchbaseConfig extends AbstractCouchbaseConfiguration {
@Autowired
private ApplicationContext context;
@Value("${app.couchbase.connection-string}")
private String connectionString;
@Value("${app.couchbase.username}")
private String username;
@Value("${app.couchbase.password}")
private String password;
@Bean
public Cluster couchbaseCluster() {
return Cluster.connect(connectionString, username, password);
}
}
存储库代码:
@Repository
public class ArLedgerRepository {
@Autowired
private Cluster couchbaseCluster;
public List<ArLedger> getAllBranchArLedgers(String branchId, String fromDate, String toDate) {
String query = Queries.GET_ALL_AR_LEDGERS_BY_BRANCH_AND_DATE_RANGE;
query = MessageFormat.format(query, branchId, fromDate, toDate);
try {
QueryResult queryResult = couchbaseCluster.query(query);
return queryResult.rowsAs(ArLedger.class);
} catch (Exception e) {
e.printStackTrace();
return Collections.emptyList();
} finally {
couchbaseCluster.disconnect();
}
}
}
my Java program is constantly getting OutOfMemoryError
, and I believe there is a memory leak somewhere. While researching this issue, multiple sites suggested the Eclipse Memory Analyzer tool, so I added the -XX:+HeapDumpOnOutOfMemoryError
flag to the command, to get the heap dump the next time the error occurs. Upon checking the dump, the objects taking up the most space were "17,481 instances of "com.couchbase.client.core.deps.org.LatencyUtils.LatencyStats", loaded by "org.springframework.boot.loader.LaunchedURLClassLoader @ 0x6c7c24510" occupy 1,978,652,856 (59.03%) bytes."
I thought this was the logger printing out too many logs, since the Java Couchbase code prints a LOT of logs on the INFO
level, so I tried setting the log level to WARN
but after trying it out, same result. Would appreciate any insight or suggestions, thank you.
EDIT: some parts of our code that calls Couchbase:
@Autowired
private CouchbaseConfig couchbaseConfig;
public List<ArLedger> getBranchArLedgers(String branchId, String fromDate, String toDate) {
String query = Queries.GET_AR_LEDGER_BY_BRANCH_AND_DATE_RANGE;
query = MessageFormat.format(query, branchId, fromDate, toDate);
Cluster cluster = null;
try {
cluster = couchbaseConfig.connectToCouchbase();
QueryResult queryResult = cluster.query(query);
return queryResult.rowsAs(ArLedger.class);
} catch (Exception e) {
e.printStackTrace();
return Collections.emptyList();
} finally {
if (cluster != null) {
cluster.disconnect();
}
}
}
And the connectToCouchbase() from the injected CouchbaseConfig:
@Value("${app.couchbase.connection-string}")
private String connectionString;
@Value("${app.couchbase.username}")
private String username;
@Value("${app.couchbase.password}")
private String password;
public Cluster connectToCouchbase() {
return Cluster.connect(connectionString, username, password);
}
EDIT 2: Updated the code to follow dnault's suggestion, and a screenshot of the error that occurs when running the code:
CouchbaseConfig:
@Configuration
public class CouchbaseConfig extends AbstractCouchbaseConfiguration {
@Autowired
private ApplicationContext context;
@Value("${app.couchbase.connection-string}")
private String connectionString;
@Value("${app.couchbase.username}")
private String username;
@Value("${app.couchbase.password}")
private String password;
@Bean
public Cluster couchbaseCluster() {
return Cluster.connect(connectionString, username, password);
}
}
The repository code:
@Repository
public class ArLedgerRepository {
@Autowired
private Cluster couchbaseCluster;
public List<ArLedger> getAllBranchArLedgers(String branchId, String fromDate, String toDate) {
String query = Queries.GET_ALL_AR_LEDGERS_BY_BRANCH_AND_DATE_RANGE;
query = MessageFormat.format(query, branchId, fromDate, toDate);
try {
QueryResult queryResult = couchbaseCluster.query(query);
return queryResult.rowsAs(ArLedger.class);
} catch (Exception e) {
e.printStackTrace();
return Collections.emptyList();
} finally {
couchbaseCluster.disconnect();
}
}
}
And the screenshot of the error that occurs when the repository method is called:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
@kei101895
AbstractCouchbaseConfiguration 中已经定义了一个 couchbaseCluster bean。如果我没有记错的话,这就是 @Autowired 将使用的集群(我相信是因为其他 @Bean 之前需要它并且已经创建了)。
该 couchbaseCluster 使用 couchbaseClusterEnvironment bean,该 bean 指定了 destroyMethod。这将确保在 ClusterEnvironment 上调用 shutdown()
要为提供的 Cluster @Bean 自定义环境,可以 @Override couchbase 配置类中的 configureEnvironment(builder) 方法。
如果您确实想要/需要拥有自己的 Cluster bean,可以在 @Bean("myBeanName") 中给它一个名称,然后通过以下方式引用它:
ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
myCluster = (Cluster) ac.getBean("myBeanName");
@kei101895
There is already a couchbaseCluster bean defined in AbstractCouchbaseConfiguration. If I'm not mistaken, that is the Cluster that @Autowired will use (I believe because it was needed previously by other @Beans and already created).
That couchbaseCluster uses the couchbaseClusterEnvironment bean which has a destroyMethod specified. This will ensure that shutdown() is called on the ClusterEnvironment
To customize the environment for the provided Cluster @Bean, one can @Override the configureEnvironment(builder) method in the couchbase config class.
If you really want/need to have your own Cluster bean, you can give it a name in @Bean("myBeanName") and then reference it with:
ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
myCluster = (Cluster) ac.getBean("myBeanName");