android - 寻找一种 GC 友好的方式来频繁替换子字符串
问题描述
我的目标是简单地替换子字符串,但非常频繁。该程序在 Android 中运行。
比如我有一个{a} is a good {b}.
带有 map=的 string = {{a}=Bob, {b}=boy}
,结果应该是Bob is a good boy.
我需要处理不同字符串的这种替换,最多 400 次 peer 秒,因为 map 的值会实时更新。
但是我使用 trie 树和 Aho-Corasick 自动机来获得高性能,这是核心片段:
val builder: StringBuilder
private fun replace(str: String): String {
if (!getFail) {
getFail()
}
var p = 1
builder.setLength(0)
for (c in str) {
builder.append(c)
if (c.toInt() !in 0..126) {
continue // ignore non-ascii char
}
var k = trie[p][c.toInt()]
while (k > 1) {
// find a tag
if (end[k] != 0) {
val last = builder.length - end[k]
// replace the tag
values[builder.sub(last, end[k])]?.let {
builder.replace1(last, end[k], it)
}
p = 0
break
}
k = fail[k] // not find
}
p = trie[p][c.toInt()]
}
return builder.toString()
}
正如你所看到的,我已经习惯StringBuilder
了重用内存,但最后我必须调用StringBuilder.toString()
返回结果,这个操作会创建一个新的字符串对象。同时结果的生命周期很短,替换函数的调用很频繁。结果JVM会频繁GC。
有什么方法可以重用短寿命结果字符串占用的内存?或者只是其他一些解决方案。
解决方案
有什么方法可以重用短寿命结果字符串占用的内存?
不。
或者只是其他一些解决方案。
如果您可以更改使用String
此方法生成的对象的代码来接受 a CharSequence
。然后你可以将StringBuilder
实例传递给它builder
,并避免toString()
调用。
问题是您将无法阻止某些东西对其进行转换CharSequence
和StringBuilder
变异。(但如果代码不是安全关键,你可以忽略它。很难做到这一点,特别是如果你CharSequence
在传递时使用接口类型StringBuilder
。)
另一个问题是调用者实际上每次都会获得具有不同状态的相同对象。它无法保持状态……除非它要求toString()
它。
但是您可能会不必要地担心性能。GC 比较擅长处理短生命周期的对象。假设一个对象在创建后的第一个 GC 循环中是不可访问的,它永远不会被标记或复制,删除它的成本将为零。大致而言,“从”空间中的可到达对象将花费您。
我会先做一些分析和 GC 监控。如果有明确的证据表明短暂的字符串会导致性能问题,请仅按照上述更改代码的方式进行。
(我的直觉是每秒 400 个短期字符串应该不是问题,假设 1)它们不是很大,并且 2)您选择了适合您的用例的 GC。)
推荐阅读
- angular - 在 Angular 应用程序的 HTML 视图/模板中,如何等待 ngFor 部分的呈现?
- ruby-on-rails - 我可以在 Rails 中拥有一个属于另一个模型的模型,它有两个不同的名称吗?
- c++ - 为什么函数指针参数不影响内存大小?
- swiftui - 如何对不同的形状使用相同的修饰符集
- terraform - 在 Terraform 中使用动态块时出错
- xml - Bing Ads API 无法检索帐户上的所有广告 - 过滤器损坏
- excel - Excel - 同一工作簿中某些工作表的总单元格
- laravel-7 - Laravel7 调用未定义的方法 Illuminate\Database\MySqlConnection::find()
- extjs - 下拉菜单未在 EXT JS 7.2 上正确保持所选值
- javascript - Angular 8 应用程序无法在 IE 中运行。(不使用 Angular CLI)