如何在Drools中管理事实插入以避免内存泄漏?

huangapple go评论107阅读模式
英文:

How should I manage fact insertion in drools to avoid a memory leak?

问题

以下是翻译好的内容:

我正在使用Drools 7.8.0来管理实时数据(每5秒钟有10000个事实)。我正在使用以下方式将它们插入工作内存:

  1. KieSession kieSession = kieContainer.newKieSession();
  2. EntryPoint entryPoint = kieSession.getEntryPoint("myData");
  3. new Thread(new Runnable() {
  4. @Override
  5. public void run() {
  6. kieSession.fireUntilHalt();
  7. }
  8. }).start();
  9. while (true) {
  10. Data data = recieveData();
  11. factHandle = entryPoint.insert(data);
  12. }

然而,这导致了内存泄漏:

共有64,994个"org.drools.core.common.EventFactHandle"实例,由"jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x702500000"加载,占用113,316,792(71.06%)字节。这些实例被一个"java.lang.Thread"实例引用,该实例由"<系统类加载器>"加载。

所以我尝试跟踪我的事实并使用update代替insert,但这影响了规则的行为,一些事实无法匹配。

  1. Map<String, FactHandle> allfacts = new HashMap<String, FactHandle>();
  2. if (!allfacts.containsKey(dataName) && data != null) {
  3. factHandle = entryPoint.insert(data);
  4. allfacts.put(dataName, factHandle);
  5. } else {
  6. entryPoint.update(allfacts.get(dataName), opcTagData);
  7. }

这里是我拥有的规则的一个示例:

  1. declare Data
  2. @role(event)
  3. @timestamp(timestamp)
  4. @expires(20s)
  5. end
  6. rule "status not available for 10 seconds"
  7. dialect "java"
  8. when
  9. d: Data(Name.contains("/Smart/Status")) from entry-point "myData"
  10. eval(!d.getValue().equals("Available"))
  11. not(
  12. Data(
  13. this.getName() == d.getName(),
  14. this.getValue().equals("Available"),
  15. this after[0s,10s] d) from entry-point "myData")
  16. then
  17. doSmthg();
  18. end

我无法找出插入事实并仍然获得预期结果而不会遇到内存泄漏的正确方法。

PS:我使用fireUntilHalt是因为在编写规则时我使用了时间操作符,我注意到使用fireAllRules不能给我预期的结果。

英文:

I am using Drools 7.8.0 to manage real time data ( 10000 facts every 5 seconds).
I am inserting them in the working memory using :

  1. KieSession kieSession = kieContainer.newKieSession();
  2. EntryPoint entryPoint = kieSession.getEntryPoint(&quot;myData&quot;);
  3. new Thread( new Runnable() {
  4. @Override
  5. public void run() {
  6. kieSession.fireUntilHalt();
  7. }
  8. } ).start();
  9. while ( true )
  10. {
  11. Data data = recieveData();
  12. factHandle=entryPoint.insert(data);
  13. }

However, this is causing a memory leak :

64,994 instances of &quot;org.drools.core.common.EventFactHandle&quot;, loaded by &quot;jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x702500000&quot; occupy 113,316,792 (71.06%) bytes. These instances are referenced from one instance of &quot;java.lang.Thread&quot;, loaded by &quot;&lt;system class loader&gt;&quot;

so I tried keeping track of my facts and using update instead of insert but this affected the rule's behavior and some facts weren't matched.

  1. Map&lt;String,FactHandle&gt; allfacts = new HashMap&lt;String,FactHandle&gt;();
  2. if( !allfacts.containsKey(dataName) &amp;&amp; data!=null)
  3. {
  4. factHandle=entryPoint.insert(data);
  5. allfacts.put(dataName,factHandle);
  6. }
  7. else
  8. {
  9. entryPoint.update(allfacts.get(dataName), opcTagData);
  10. }
  11. }
  12. catch(Exception ex)
  13. {
  14. //error
  15. }

Here's an example of the rules I have:

  1. declare Data
  2. @role( event )
  3. @timestamp( timestamp )
  4. @expires( 20s )
  5. end
  6. rule &quot;status not available for 10 seconds &quot;
  7. dialect &quot;java&quot;
  8. when
  9. d: Data(Name.contains(&quot;/Smart/Status&quot;)) from entry-point &quot;myData&quot;
  10. eval(!d.getValue().equals(&quot;Available&quot;))
  11. not(
  12. Data(
  13. this.getName() == d.getName(),
  14. this.getValue().equals(&quot;Available&quot;),
  15. this after[0s,10s] d) from entry-point &quot;myData&quot;)
  16. then
  17. doSmthg();
  18. end

I can't figure out what's the right way to to insert the facts and still get the expected result without facing a memory leak

PS:
I'm using fireUntilHalt because I used Temporal Operators when writing the rules and I noticed that using fireallrules does not give me the expected result.

答案1

得分: 2

以下是您提供的内容的翻译部分:

  1. 我测试了您的规则并进行了撤销,对我起作用。每个事件在20秒内被撤销。
  2. 您能确认您使用了 `stream` [模式](https://docs.jboss.org/drools/release/7.43.1.Final/drools-docs/html_single/index.html#cep-modes-con_decision-engine) 吗?
  3. 使用系统属性设置流模式
  4. drools.eventProcessingMode=stream
  5. 使用Java客户端API设置流模式
  6. import org.kie.api.conf.EventProcessingOption;
  7. import org.kie.api.KieBaseConfiguration;
  8. import org.kie.api.KieServices.Factory;
  9. KieBaseConfiguration config = KieServices.Factory.get().newKieBaseConfiguration();
  10. config.setOption(EventProcessingOption.STREAM);
  11. 使用项目的 kmodule.xml 文件设置流模式
  12. <kmodule>
  13. ...
  14. <kbase name="KBase2" default="false" eventProcessingMode="stream" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
  15. ...
  16. </kbase>
  17. ...
  18. </kmodule>
  19. ---
  20. 在之前的 drools 版本中,显式的事件撤销效果更好
  21. rule "retract expired events"
  22. salience 1
  23. duration 20000
  24. when
  25. d: Data() from entry-point "myData"
  26. then
  27. retract(d);
  28. end
  29. ---
  30. 这是我如何测试您的代码
  31. test.drl
  32. package draft;
  33. dialect "java";
  34. declare Data
  35. @role(event)
  36. @timestamp(timestamp)
  37. @expires(20s)
  38. end
  39. rule "retract expired events"
  40. salience 1
  41. duration 20000
  42. when
  43. d: Data() from entry-point "test it"
  44. then
  45. retract(d);
  46. end
  47. rule "status not available for 10 seconds"
  48. when
  49. d: Data(Name.contains("/Smart/Status")) from entry-point "myData"
  50. eval(!d.getValue().equals("Available"))
  51. not(
  52. Data(
  53. this.getName() == d.getName(),
  54. this.getValue().equals("Available"),
  55. this after[0s,10s] d) from entry-point "myData")
  56. then
  57. System.out.println("alert");
  58. end
  59. PlaygroundTest.java
  60. @DroolsSession("test.drl")
  61. public class PlaygroundTest {
  62. @Rule
  63. public DroolsAssert drools = new DroolsAssert();
  64. @Test
  65. public void testIt() {
  66. for (int i = 0; i < 5; i++) {
  67. drools.insertAndFireAt("myData", new Data(new Date(SECONDS.toMillis(i * 5)), "/Smart/Status", "Unavailable"));
  68. drools.advanceTime(5, SECONDS);
  69. drools.printFacts();
  70. }
  71. drools.assertFactsCount(3);
  72. drools.advanceTime(5, SECONDS);
  73. drools.printFacts();
  74. drools.assertFactsCount(2);
  75. drools.advanceTime(5, SECONDS);
  76. drools.printFacts();
  77. drools.assertFactsCount(1);
  78. drools.advanceTime(5, SECONDS);
  79. drools.printFacts();
  80. drools.assertFactsCount(0);
  81. }
  82. }
  83. Data.java
  84. public class Data {
  85. private Date timestamp;
  86. private String name;
  87. private String value;
  88. public Data(Date timestamp, String name, String value) {
  89. this.timestamp = timestamp;
  90. this.name = name;
  91. this.value = value;
  92. }
  93. public Date getTimestamp() {
  94. return timestamp;
  95. }
  96. public String getName() {
  97. return name;
  98. }
  99. public String getValue() {
  100. return value;
  101. }
  102. }
  103. stdout
  104. 00:00:00 --> inserted: Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
  105. 00:00:00 --> fireAllRules
  106. 00:00:05 Facts (1):
  107. Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
  108. ...
  109. 00:00:40 Facts (0):
英文:

I tested your rule and retraction works for me. Each event was retracted in 20s.
Can you confirm you use stream mode?

Set stream mode using system property

  1. drools.eventProcessingMode=stream

Set stream mode using Java client API

  1. import org.kie.api.conf.EventProcessingOption;
  2. import org.kie.api.KieBaseConfiguration;
  3. import org.kie.api.KieServices.Factory;
  4. KieBaseConfiguration config = KieServices.Factory.get().newKieBaseConfiguration();
  5. config.setOption(EventProcessingOption.STREAM);

Set stream mode using project kmodule.xml file

  1. &lt;kmodule&gt;
  2. ...
  3. &lt;kbase name=&quot;KBase2&quot; default=&quot;false&quot; eventProcessingMode=&quot;stream&quot; packages=&quot;org.domain.pkg2, org.domain.pkg3&quot; includes=&quot;KBase1&quot;&gt;
  4. ...
  5. &lt;/kbase&gt;
  6. ...
  7. &lt;/kmodule&gt;

It happened in previous versions of drools that explicit event retraction worked better

  1. rule &quot;retract expired events&quot;
  2. salience 1
  3. duration 20000
  4. when
  5. d: Data() from entry-point &quot;myData&quot;
  6. then
  7. retract(d);
  8. end

This is how I tested your code

test.drl

  1. package draft;
  2. dialect &quot;java&quot;
  3. declare Data
  4. @role(event)
  5. @timestamp(timestamp)
  6. @expires(20s)
  7. end
  8. rule &quot;retract expired events&quot;
  9. salience 1
  10. duration 20000
  11. when
  12. d: Data() from entry-point &quot;test it&quot;
  13. then
  14. retract(d);
  15. end
  16. rule &quot;status not available for 10 seconds&quot;
  17. when
  18. d: Data(Name.contains(&quot;/Smart/Status&quot;)) from entry-point &quot;myData&quot;
  19. eval(!d.getValue().equals(&quot;Available&quot;))
  20. not(
  21. Data(
  22. this.getName() == d.getName(),
  23. this.getValue().equals(&quot;Available&quot;),
  24. this after[0s,10s] d) from entry-point &quot;myData&quot;)
  25. then
  26. System.out.println(&quot;alert&quot;);
  27. end

PlaygroundTest.java

  1. @DroolsSession(&quot;test.drl&quot;)
  2. public class PlaygroundTest {
  3. @Rule
  4. public DroolsAssert drools = new DroolsAssert();
  5. @Test
  6. public void testIt() {
  7. for (int i = 0; i &lt; 5; i++) {
  8. drools.insertAndFireAt(&quot;myData&quot;, new Data(new Date(SECONDS.toMillis(i * 5)), &quot;/Smart/Status&quot;, &quot;Unavailable&quot;));
  9. drools.advanceTime(5, SECONDS);
  10. drools.printFacts();
  11. }
  12. drools.assertFactsCount(3);
  13. drools.advanceTime(5, SECONDS);
  14. drools.printFacts();
  15. drools.assertFactsCount(2);
  16. drools.advanceTime(5, SECONDS);
  17. drools.printFacts();
  18. drools.assertFactsCount(1);
  19. drools.advanceTime(5, SECONDS);
  20. drools.printFacts();
  21. drools.assertFactsCount(0);
  22. }
  23. }

Data.java

  1. public class Data {
  2. private Date timestamp;
  3. private String name;
  4. private String value;
  5. public Data(Date timestamp, String name, String value) {
  6. this.timestamp = timestamp;
  7. this.name = name;
  8. this.value = value;
  9. }
  10. public Date getTimestamp() {
  11. return timestamp;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public String getValue() {
  17. return value;
  18. }
  19. }

stdout

  1. 00:00:00 --&gt; inserted: Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
  2. 00:00:00 --&gt; fireAllRules
  3. 00:00:05 Facts (1):
  4. Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
  5. 00:00:05 --&gt; inserted: Data[timestamp=Thu Jan 01 02:00:05 EET 1970,name=/Smart/Status,value=Unavailable]
  6. 00:00:05 --&gt; fireAllRules
  7. 00:00:10 &lt;-- &#39;status not available for 10 seconds&#39; has been activated by the tuple [Data]
  8. alert
  9. 00:00:10 Facts (2):
  10. Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
  11. Data[timestamp=Thu Jan 01 02:00:05 EET 1970,name=/Smart/Status,value=Unavailable]
  12. 00:00:10 --&gt; inserted: Data[timestamp=Thu Jan 01 02:00:10 EET 1970,name=/Smart/Status,value=Unavailable]
  13. 00:00:10 --&gt; fireAllRules
  14. 00:00:15 &lt;-- &#39;status not available for 10 seconds&#39; has been activated by the tuple [Data]
  15. alert
  16. 00:00:15 Facts (3):
  17. Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
  18. Data[timestamp=Thu Jan 01 02:00:05 EET 1970,name=/Smart/Status,value=Unavailable]
  19. Data[timestamp=Thu Jan 01 02:00:10 EET 1970,name=/Smart/Status,value=Unavailable]
  20. 00:00:15 --&gt; inserted: Data[timestamp=Thu Jan 01 02:00:15 EET 1970,name=/Smart/Status,value=Unavailable]
  21. 00:00:15 --&gt; fireAllRules
  22. 00:00:20 &lt;-- &#39;status not available for 10 seconds&#39; has been activated by the tuple [Data]
  23. alert
  24. 00:00:20 Facts (3):
  25. Data[timestamp=Thu Jan 01 02:00:05 EET 1970,name=/Smart/Status,value=Unavailable]
  26. Data[timestamp=Thu Jan 01 02:00:10 EET 1970,name=/Smart/Status,value=Unavailable]
  27. Data[timestamp=Thu Jan 01 02:00:15 EET 1970,name=/Smart/Status,value=Unavailable]
  28. 00:00:20 --&gt; inserted: Data[timestamp=Thu Jan 01 02:00:20 EET 1970,name=/Smart/Status,value=Unavailable]
  29. 00:00:20 --&gt; fireAllRules
  30. 00:00:25 &lt;-- &#39;status not available for 10 seconds&#39; has been activated by the tuple [Data]
  31. alert
  32. 00:00:25 Facts (3):
  33. Data[timestamp=Thu Jan 01 02:00:10 EET 1970,name=/Smart/Status,value=Unavailable]
  34. Data[timestamp=Thu Jan 01 02:00:15 EET 1970,name=/Smart/Status,value=Unavailable]
  35. Data[timestamp=Thu Jan 01 02:00:20 EET 1970,name=/Smart/Status,value=Unavailable]
  36. 00:00:30 &lt;-- &#39;status not available for 10 seconds&#39; has been activated by the tuple [Data]
  37. alert
  38. 00:00:30 Facts (2):
  39. Data[timestamp=Thu Jan 01 02:00:15 EET 1970,name=/Smart/Status,value=Unavailable]
  40. Data[timestamp=Thu Jan 01 02:00:20 EET 1970,name=/Smart/Status,value=Unavailable]
  41. 00:00:35 Facts (1):
  42. Data[timestamp=Thu Jan 01 02:00:20 EET 1970,name=/Smart/Status,value=Unavailable]
  43. 00:00:40 Facts (0):

huangapple
  • 本文由 发表于 2020年9月16日 18:05:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/63917707.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定