垃圾回收对于Springboot Maven项目从不运行

问题描述 投票:4回答:1

我有一个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");
        }
    }
java spring-boot garbage-collection heap-memory
1个回答
0
投票

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

[当您使用并发收集器时(例如ZGCShenandoah),无论它们是否运行,都没有关系[;这是因为它们是concurrent:它们在您的应用程序运行时运行。它们确实具有stop-the-world暂停-但它们很小(例如在某些情况下不同于G1GC)。由于这种并发性,它们被迫“每X秒”运行; Shenandoah具有-XX:ShenandoahGuaranteedGCInterval=10000(我们在生产中使用它)。但是我假设您使用的是G1GC(即,如果您根本不启用GC,就会得到此信息)。该特定GC是大多

并发的,并且是

世代。它将堆拆分为youngold区域,并独立收集它们。年轻区域是在STW暂停下收集的,而Full GC(收集旧区域)是主要并发的:从字面上看,它可以将STW暂停延长到几分钟,但这不是一般情况。 >所以,当您使用G1GC时,当all年轻的Eden区域(年轻的区域在Eden和Survivor中分开)将触发年轻的GC周期。当发生以下三种情况之一时,将触发完整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的一种简单且不完整的图,主要是因为这三个中的任何一个实际上会触发一个mark阶段(整个Full GC的特定部分),会根据从区域收集的数据来决定下一步要做什么。通常,它会立即触发

young GC

,然后立即触发

then mixed Collection,但可能会选择其他路径(再次基于GC所具有的数据)。

© www.soinside.com 2019 - 2024. All rights reserved.