Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: OPM memory leak #1935

Open
2 of 16 tasks
botteonr opened this issue Dec 12, 2024 · 1 comment
Open
2 of 16 tasks

[Bug]: OPM memory leak #1935

botteonr opened this issue Dec 12, 2024 · 1 comment
Labels
bug java Pull requests that update Java code Modbus https://plc4x.apache.org/users/protocols/modbus.html

Comments

@botteonr
Copy link

What happened?

Production use case:

  • Constantly reading and writing (every second) from and to a Plc via modbus tcp.

Issue:

  • After running for days (or weeks depend on -Xmx) the application crashes because an OutOfMemoryError.

Comparing dumps (from production) show an increase of byte[] objects like:
java.lang.String#45053 : FooRxEntity$ByteBuddy$opFq0T9M$auxiliary$5LGzfXOE.

The ByteBuddy instances are created here:
org.apache.plc4x.java.opm.PlcEntityManager#connect(java.lang.Class<T>, java.lang.String, T)

therefore I think that PlcEntityManager is responsible for the leak.

Code to reproduce the issue:

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import org.apache.plc4x.java.DefaultPlcDriverManager;
import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
import org.apache.plc4x.java.api.types.PlcResponseCode;
import org.apache.plc4x.java.mock.connection.MockConnection;
import org.apache.plc4x.java.mock.connection.MockDevice;
import org.apache.plc4x.java.opm.OPMException;
import org.apache.plc4x.java.opm.PlcEntityManager;
import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
import org.apache.plc4x.java.spi.values.PlcSTRING;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class Plc4jMockConnectionTest {

  @Test
  void shouldRead() throws PlcConnectionException {
    MockDevice mockDevice = Mockito.mock(MockDevice.class);
    DefaultPlcDriverManager driverManager = new DefaultPlcDriverManager();
    MockConnection connection = (MockConnection) driverManager.getConnection("mock:test");
    when(mockDevice.read(any())).thenAnswer(invocation -> new ResponseItem(PlcResponseCode.OK, new PlcSTRING("1")));
    connection.setDevice(mockDevice);

    PlcEntityManager entityManager = new PlcEntityManager(driverManager);

    while (true) {
      try {
        FooRxEntity read = entityManager.read(FooRxEntity.class, "mock:test");
        Thread.sleep(10);
      } catch (OPMException e) {
        throw new RuntimeException(e);
      } catch (InterruptedException e) {
        throw new RuntimeException(e);
      }
    }
  }
}

And the entity:

import org.apache.plc4x.java.opm.PlcEntity;
import org.apache.plc4x.java.opm.PlcTag;

@PlcEntity
public class FooRxEntity {
  @PlcTag("input-register:1:WORD")
  private short bp102;
  @PlcTag("input-register:2:WORD")
  private short bp105;
  @PlcTag("input-register:3:WORD")
  private short bp112;
  @PlcTag("input-register:4:WORD")
  private short bp115;
  @PlcTag("input-register:5:WORD")
  private short bp122;
  @PlcTag("input-register:6:WORD")
  private short bp125;
  @PlcTag("input-register:7:WORD")
  private short bp360;
  @PlcTag("input-register:8:WORD")
  private short bp260;
  @PlcTag("input-register:9:WORD")
  private short bf102;
  @PlcTag("input-register:10:WORD")
  private short bf112;
  @PlcTag("input-register:11:WORD")
  private short bf122;
  @PlcTag("input-register:21:WORD")
  private short bt220;
  @PlcTag("input-register:22:WORD")
  private short bt230;
  @PlcTag("input-register:23:WORD")
  private short bt260;
  @PlcTag("input-register:24:WORD")
  private short bt320;
  @PlcTag("input-register:25:WORD")
  private short bt330;
  @PlcTag("input-register:26:WORD")
  private short bt360;
  @PlcTag("holding-register:2049:WORD")
  private int bf102Setpoint;
  @PlcTag("holding-register:2050:WORD")
  private int bf112Setpoint;
  @PlcTag("holding-register:2051:WORD")
  private int bf122Setpoint;
  @PlcTag("holding-register:2057:WORD")
  private short qm;
}

The test is started with VM options -Xms128m -Xmx128m. After ~4 minutes OOM is thrown.
image

I can reproduce the OOE with a real connection. This take a lot more time because the plc support a max reading rate of ~300ms.
Real test:

  @Test
  void shouldRead() {
    PlcDriverManager driverManager = new DefaultPlcDriverManager();
    PlcConnectionManager connectionManager = driverManager.getConnectionManager();
    PlcEntityManager entityManager = new PlcEntityManager(connectionManager);

    while (true) {
      try {
        FooRxEntity read = entityManager.read(FooRxEntity.class, "modbus-tcp:tcp://192.168.100.222:502");
        Thread.sleep(300);
      } catch (OPMException e) {
        throw new RuntimeException(e);
      } catch (InterruptedException e) {
        throw new RuntimeException(e);
      }
    }
  }

Mock dump:
heapdump-1733998935197.zip

Production dump:
heapdump-1732691913936.zip

Please let me know if you need more details and thank you in advance.

Version

v0.12.0

Programming Languages

  • plc4j
  • plc4go
  • plc4c
  • plc4net

Protocols

  • AB-Ethernet
  • ADS /AMS
  • BACnet/IP
  • CANopen
  • DeltaV
  • DF1
  • EtherNet/IP
  • Firmata
  • KNXnet/IP
  • Modbus
  • OPC-UA
  • S7
@botteonr botteonr added the bug label Dec 12, 2024
@ottlukas ottlukas added java Pull requests that update Java code Modbus https://plc4x.apache.org/users/protocols/modbus.html labels Dec 12, 2024
@chrisdutz
Copy link
Contributor

The OPM module hasn't seen any serious contribution for many years. This is due to the fact, that the person who built it, no longer is active in the project.

As far as I know, there isn't anyone else really deeply involved in this. I think I was the only one occasionally working on it.

However have I stopped contributing to the project for free ... I would be willing to have a look at this and your other issue, for a donation of at least 60€ to my BuyMeACoffee page https://buymeacoffee.com/christoferu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug java Pull requests that update Java code Modbus https://plc4x.apache.org/users/protocols/modbus.html
Projects
None yet
Development

No branches or pull requests

3 participants