gpt4 book ai didi

java - Spring Boot Maven 项目的垃圾收集从不运行

转载 作者:行者123 更新时间:2023-12-02 15:16:01 26 4
gpt4 key购买 nike

我有一个 Springboot Maven 项目,它使用 @JmsListener 从队列中读取消息。

如果没有事件传入,堆内存会缓慢增加。当消息到来时,堆内存会快速增加。但堆内存永远不会下降(检查下图)。

如果我在接收器方法的末尾添加 System.gc() 垃圾收集器将按预期完成其工作。但这绝对不是一个好的做法。

如何确保 gc 在适当的时间运行。任何帮助将不胜感激!

堆内存使用

Heap Memory Usage

接收方方法

@JmsListener(destination = "${someDestination}", containerFactory = "jmsListenerContainerFactory")
public void receiveMessage(Message message){
if (message instanceof BytesMessage) {
try {
List<Trackable> myList;

BytesMessage byteMessage = (BytesMessage) message;
byte[] byteData = new byte[(int) byteMessage.getBodyLength()];
byteMessage.readBytes(byteData);

DocumentBuilder dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = dBuilder.parse(new InputSource(new StringReader(new String(byteData))));

TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Transformer transformer = factory.newTransformer();

StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(doc.getElementsByTagName(SOME_TAG_NAME).item(0)), new StreamResult(writer));
String outputXmlString = writer.getBuffer().toString();

XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
XMLStreamReader xmlReader = xmlFactory.createXMLStreamReader(new StringReader(outputXmlString));

JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);

MyEvent myEvent = ((JAXBElement<MyEvent>) jaxbContext.createUnmarshaller().unmarshal(xmlReader)).getValue();
myList = myService.saveEvent(myEvent);

LOGGER.info(String.format("Received message with EventID: %s and successfully inserted into database", myEvent.getID()));

} catch (Exception e) {
LOGGER.error(e.getClass().getCanonicalName() + " in Receiver: ", e);
}
} else {
LOGGER.error("Received unsupported message format from MQ");
}
}

最佳答案

为什么?因为JVM决定(基于其启发式)现在还不是运行的时间。何时运行取决于堆大小和 GC 算法。一般来说,运行 GC 周期绝不是免费操作 - 它至少需要 GC 周期 + 停止应用程序一段时间(称为 stop-the-world 事件)。因此,GC 算法会在需要时运行。

当您使用并发收集器(例如 ZGCShenandoah)时,它们是否运行并不重要。这是因为它们是并发的:它们在您的应用程序运行时运行。他们确实有stop-the-world暂停 - 但这些非常小(与 G1GC 例如在某些情况下不同)。由于这种并发性,它们可以被迫“每X秒”运行一次; Shenandoah-XX:ShenandoahGuaranteedGCInterval=10000 (我们在生产中使用它)。

但我假设您正在使用G1GC (也就是说,如果您根本不启用 GC,就会得到这样的结果)。这个特定的 GC 大部分是并发的,并且是分代的。它将堆分为年轻区域并独立收集它们。年轻区域收集在STW下暂停,同时 Full GC (收集旧区域)大部分是并发的:它可以拉伸(stretch) STW从字面上看,暂停到几分钟,但这不是一般情况。

所以,当您使用G1GC时,当所有年轻Eden区域(年轻区域在Eden和Survivor中进一步 split )满时,将会触发年轻GC周期。当这 3 种情况之一发生时,将触发 Full GC 周期:

 1) IHOP is reached 
2) G1ReservePercent is reached
3) a humongous allocation happens (an allocation that spans across multiple regions - think huge Objects).

但这只是一幅关于 GC cycle 何时出现的简单且不完整的图景。发生在G1GC ,主要是因为这 3 个中的任何一个实际上都会触发 mark阶段(整个 Full GC 的某个部分),它将根据从区域收集的数据决定下一步做什么。它通常会立即触发年轻GC,然后然后 mixed Collection ,但可能会选择不同的路径(同样,基于 GC 拥有的数据)。

所以总的来说,对于 GC cycle 来说,堆上的压力太小了。大多数时候,这正是您想要的。

关于java - Spring Boot Maven 项目的垃圾收集从不运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59963659/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com