【问题标题】:How to match regular expression without creating objects in Java?如何匹配正则表达式而不在 Java 中创建对象?
【发布时间】:2012-02-28 04:31:36
【问题描述】:

我正在研究一个正则表达式匹配函数。问题是,这个函数将在嵌套循环中被框架调用。如果创建了临时对象,GC会造成很大的性能问题。

是否可以在不创建临时对象(Pattern、Matcher)的情况下处理正则表达式? 重写正则表达式类是我最后的选择...

【问题讨论】:

  • 1) GC 永远不会导致性能问题! 2) 你不能仅仅因为你没有使用临时对象就假设在你的循环期间不会调用 GC。 3)如果您希望对象持久存在,那么您应该stackoverflow.com/questions/1329926/…
  • @Ahmed-Masud :从技术上讲这是不正确的,因为主(完整)GC 周期取决于分配给 JVM 的内存量,更多的内存意味着更多的时间来完成循环- 对系统有一些影响
  • @BigFatBaby 我同意分配的内存数量和块将导致 GC 线程更努力地工作(或不工作)。我在 1) 中的观点是,要么系统对于应用程序来说足够强大,要么不够强大,并且应该在启动时调整 GC。如果铁资源枯竭,那么任何方法无论如何都充满危险。是否持有所有对象的 refs 以避免 GC(m​​em hog);或者使用 JNI 编写外部方法(在本地运行)并完全绕过 GC 之一仍然受到可用系统资源的限制。
  • @Ahmed-Masud :经验法则是 - 如果 GC 给你带来麻烦,你做错了......我同意......但是我是来帮助解决问题的(专门询问) ...对于常见做法,Stack Exchange 上还有其他网站 :)

标签: java regex


【解决方案1】:

引用一句老话:

让它发挥作用,让它正确,让它快速。 (按顺序)

因此,在进行任何繁重的优化步骤之前,只需编写初始简单的适当代码(在这种情况下,如果可以的话,这将涉及预编译您的模式)。运行一些测试,看看性能是否不足,然后优化正则表达式部分是否是瓶颈。

如果对象创建(和清理)是一个严重的瓶颈(与实际的正则表达式解析本身相比),那么您可能需要实现自己的使用对象池的解决方案(因此不会创建对象,只需重置和从池中重复使用)。我怀疑这是否会带来任何严重的性能提升,因此您应该首先进行基准测试,看看甚至可能获得多少收益(如果您将对象创建/清理性能提高 50%,是否值得?)。

【讨论】:

  • 谢谢。我的同事在他们之前的工作中发现了与 gc 相关的问题。因此,团队中的成员必须避免它们。但你是对的。我会先让它工作,然后再测试。
【解决方案2】:

您最好的办法是在问题出现时立即处理 - 他们可能不会。大约 10 年前,围绕 GC 处理大量小型活动对象的性能问题是一个问题,但现在它已经非常擅长了。

如果您确实需要优化,那么这应该以更改 GC 选项的形式 - 例如年轻代的大小,而不是尝试在代码中进行优化。

【讨论】:

  • 这是一个需要处理大量数据的极端情况。大量的小物件会造成麻烦。我们尝试了 GC 选项,但无法全部解决。
【解决方案3】:

Matcher 对象不是线程安全的,因此您不能重复使用它们,除非您调用 reset() 方法(在单个线程中应该可以正常工作) - 请参阅 Is Java Regex Thread Safe?

【讨论】:

    【解决方案4】:

    这听起来像是过早的优化。

    尽可能编写最简单的代码,然后在实际设置中对其进行分析,并查看性能或内存分配模式是否存在任何问题。如果有,请解决您发现的具体问题。

    现代 JVM 非常擅长垃圾收集短期对象。

    【讨论】:

      【解决方案5】:

      您可以预编译您的正则表达式,如果您多次重复使用同一个正则表达式,这很有意义。

      代替

      boolean foundMatch = subjectString.matches("a.*b");
      

      (无论如何都会创建一个临时编译的Pattern),你可以使用

      Pattern regex = Pattern.compile("a.*b");
      // loop here
      // do something...
          Matcher regexMatcher = regex.matcher(subjectString);
          boolean foundMatch = regexMatcher.matches()
      // loop end
      

      不过,很难说是否会有任何相关的性能优势。

      【讨论】:

      • 我先编译试试。谢谢。
      【解决方案6】:

      在我看来,您有 2 个可行的选择:

      1. 通过查看源代码编写您自己的匹配正则表达式的逻辑:PatternMatcher
      2. 通过运行它们对应的finalize() 函数,而不是等待 GC 运行它,在完成这些对象后显式启动这些对象的集合。

      优点和缺点

      1. 很多工作需要在未来进行测试和维护,但是您可以完全控制您正在尝试执行的操作。

      2. 不建议干扰GC、清洁溶液和简单溶液的工作

      【讨论】:

      • 嗯...重写它们不会那么容易。
      • @user1192878:确实——这就是我建议第二种方法的原因
      猜你喜欢
      • 2017-06-30
      • 1970-01-01
      • 1970-01-01
      • 2015-03-24
      • 2015-06-03
      • 1970-01-01
      • 1970-01-01
      • 2012-10-26
      • 2011-03-30
      相关资源
      最近更新 更多