【问题标题】:Memory efficient way to replace string in Java在Java中替换字符串的内存有效方法
【发布时间】:2016-10-28 22:02:49
【问题描述】:

我们即将发布一个网站,该网站一次最多可显示 500 张图片,这些图片存储在亚马逊上。由于 url 使用“http”而不是“https”存储在我们的数据库中,因此每次检索图像 url 时,我都需要将“http”替换为“https”。这是当前代码:

static Pattern p = Pattern.compile("http");

Matcher m = p.matcher(urlSmall);;
String secureUrlSmall = m.replaceFirst("https");
return secureUrlSmall;

我担心的是,创建这么多 String 对象会占用 Java 堆空间。例如,是否有更好的解决方案涉及 StringBuilder?

【问题讨论】:

  • 使用StringBuilderMatcher 的区别在哪里?两者都建立了一个新的String。不管你使用哪一个,因为两者都会用新的String-Objects 污染堆。而且我怀疑对数据库中的值进行简单更新会那么复杂。
  • 我非常怀疑这是否重要(与您网站上的其他事情相比,例如与数据库交谈或将 HTML 发送到浏览器)。 FWIW,您不必涉及模式匹配器,一个简单的 return urlSmall.replace("http://", "https://"); 应该可以。
  • 这在我看来是合理的,使用 StringBuilder 仍然需要转换为 String
  • return 语句的存在表明m 是一个本地 变量。因此,匹配器对象将被实例化、使用,然后立即释放,使其可用于垃圾回收。据推测,弦乐也将同样短暂。我在这里看不到任何可能“吃掉”堆空间的东西。
  • 在数据库中更新您的网址不是更有意义吗?为什么要保留不正确的 url 并在 Java 中每次更新?

标签: java regex memory jvm heap-memory


【解决方案1】:

除了考虑 Java 字符串池维护之外,还有几个解决方案。由于基于专家 cmets,我们对此无能为力。架构指导一直是通过使用适当的建模来避免过度处理数据。

我认为 Java 中的改进是不可行的,但如果我遇到这个问题,我会尝试以下方法:

我问自己一个问题 - 这些 URL 的模型是否正确?如果要求在不同情况下将 http 或 https 附加到“主要”部分(域名/完整 URL)。我宁愿将 URL 的“主要”部分单独存储在数据库中,并在选择期间将 http/https 附加到它们。可以有多种方法来做到这一点。

如果此时无法更改数据库模型, 在选择查询期间将 http 替换为 https 的其他方式。

【讨论】:

    【解决方案2】:

    使用正则表达式可能相对昂贵。如果你经常调用它,纯字符串操作会快得多

    if (urlSmall.startsWith("http:"))
       return "https:" + urlSmall.substring(5);
    if (urlSmall.startSwith("https:"))
       return urlSmall;
    // error
    

    我担心创建这么多 String 对象会占用 Java 堆空间。

    这样做会产生大量垃圾,但仅从数据库中获取原始urlSmall 就会产生更多垃圾。

    除非您要将数据库缓存在内存中,否则我会接受使用数据库很可能是足够快而不是尽可能快的解决方案。

    【讨论】:

    • 将正则表达式与预构建的Pattern 结合使用并不一定很昂贵,考虑到幕后发生的事情(与手动代码相同的字符串连接操作),尤其是在适当的情况下使用Pattern.LITERAL .如果你想打败它,你可以省略substring创建的临时String对象:return new StringBuilder(urlSmall.length()+1).append("https:") .append(urlSmall, 5, urlSmall.length()).toString();
    • @Holger 虽然文字模式非常昂贵,但它仍然会创建许多您在使用时不需要的对象。
    【解决方案3】:

    如果您要创建大量字符串,我建议您创建一个字符串池。它将有助于内存管理,因为您可以控制一次可以存在的最大字符串数,并且它们将被更有效地使用,因为它们在不使用时可以重复使用。

    【讨论】:

    • 架构指导是避免过多的代码。根据最佳编程实践,我们需要使用现有的 API/库。在这种情况下,它原来是在 Oracle 中。我们编写的代码越多,错误越多,因此它为所有团队提供了更多的维护。
    • 实际上,这可能不是一个坏主意。您可以基于LinkedHashMap 创建一个LRU 缓存,其中http: URL 作为键,https: 作为值。 computeIfAbsent() 方法可以执行 replaceFirst() 来生成值。如果这真的是一个需要解决的问题,那将是一个很好的解决方案。
    • JVM 保留的字符串与对它们的强引用一样多。 “字符串池”不能改变它的任何东西,它所能做的就是保存对其他未使用字符串的更多引用。
    猜你喜欢
    • 2012-01-05
    • 1970-01-01
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-27
    • 2018-03-28
    相关资源
    最近更新 更多