[英]Analyzing heap dump from OutOfMemoryError in Java
my Java program is constantly getting OutOfMemoryError
, and I believe there is a memory leak somewhere.我的 Java 程序不断出现
OutOfMemoryError
,我相信某处存在 memory 泄漏。 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.在研究这个问题时,多个站点建议使用 Eclipse Memory Analyzer 工具,因此我在命令中添加了
-XX:+HeapDumpOnOutOfMemoryError
标志,以在下次发生错误时获取堆转储。 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."检查转储后,占用最多空间的对象是“com.couchbase.client.core.deps.org.LatencyUtils.LatencyStats 的 17,481 个实例”,由“org.springframework.boot.loader.LaunchedURLClassLoader @ 0x6c7c24510”加载占用 1,978,652,856 (59.03%) 字节。”
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.我认为这是记录器打印了太多日志,因为 Java Couchbase 代码在
INFO
级别打印了很多日志,所以我尝试将日志级别设置为WARN
,但在尝试之后,结果相同。 Would appreciate any insight or suggestions, thank you.将不胜感激任何见解或建议,谢谢。
EDIT: some parts of our code that calls Couchbase:编辑:我们调用 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:以及注入的 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);
}
EDIT 2: Updated the code to follow dnault's suggestion, and a screenshot of the error that occurs when running the code:编辑 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);
}
}
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:以及调用repository方法时出现的错误截图:
@kei101895 @kei101895
There is already a couchbaseCluster bean defined in AbstractCouchbaseConfiguration. AbstractCouchbaseConfiguration 中已经定义了一个 couchbaseCluster bean。 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).
如果我没记错的话,那是@Autowired 将使用的集群(我相信是因为其他@Beans 之前需要它并且已经创建了)。
That couchbaseCluster uses the couchbaseClusterEnvironment bean which has a destroyMethod specified.该 couchbaseCluster 使用指定了 destroyMethod 的 couchbaseClusterEnvironment bean。 This will ensure that shutdown() is called on the ClusterEnvironment
这将确保在 ClusterEnvironment 上调用 shutdown()
@Bean(destroyMethod = "shutdown")
public ClusterEnvironment couchbaseClusterEnvironment() {...
To customize the environment for the provided Cluster @Bean, one can @Override the configureEnvironment(builder) method in the couchbase config class.要为提供的 Cluster @Bean 自定义环境,可以在 couchbase 配置 class 中 @Override configureEnvironment(builder) 方法。
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:如果您真的想要/需要拥有自己的 Cluster bean,您可以在 @Bean("myBeanName") 中给它起一个名字,然后用以下方法引用它:
ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class); ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class); myCluster = (Cluster) ac.getBean("myBeanName");
myCluster = (Cluster) ac.getBean("myBeanName");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.