【学到一个新名词】String interning(字符串驻留/字符串内部化)

这篇具有很好参考价值的文章主要介绍了【学到一个新名词】String interning(字符串驻留/字符串内部化)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!

  • cnblogs博客
  • zhihu
  • Github
  • 公众号:一本正经的瞎扯
    【学到一个新名词】String interning(字符串驻留/字符串内部化)

在阅读 VictoriaMetrics v1.95.1 的命令行手册的时候,发现这样一段:

  -internStringCacheExpireDuration duration
     The expiry duration for caches for interned strings. See https://en.wikipedia.org/wiki/String_interning . See also -internStringMaxLen and -internStringDisableCache (default 6m0s)

什么是 String interning 呢?我通过了 wiki 链接学习了一下。
并且,我还找到了一个使用 String interning 技术的 golang 项目:https://github.com/josharian/intern . 作者还写了 blog: Interning strings in Go 来进一步介绍细节。

String interning 可以翻译为 字符串驻留 或者 字符串内部化。这个技巧用于节约频繁出现的字符串的空间占用,还可以用于频繁出现的字符串的比较的加速。
它的处理思路如下:

  1. 首先有一个全局的线程安全的键值对的字符串池;
类似于: map[string]string

然后把出现频率超级高的字符串存储在其中。

  1. 当出现新的字符串的时候,要先去字符串池中匹配。
    匹配到以后,程序就可以引用字符串池中的对象,而把当前引用的对象释放掉。
    当存在大量的这样内容相同的字符串的时候,这样做无疑是可以节省空间的。
    在这样的场景下,相当于时间换空间。

  2. 当字符串都来自字符串池,且需要频繁比较的时候,直接比较指针就可以确定是否是同一个字符串,而无需逐个字符比较。
    在这样的场景下,相当于空间换时间。

让我们再看看那个简单的 golang 实现的字符串内部化的源码:
see: https://github.com/josharian/intern/blob/master/intern.go

package intern

import "sync"

var (
	pool sync.Pool = sync.Pool{   // 作者想用 sync.Pool 来解决不引用时候的释放问题。但是并发环境下可能导致分配了多个键值对的字符串池。
		New: func() interface{} {    // sync.Pool 能够在并发环境下工作,不管怎么说,并发情况下使用不会出错。
			return make(map[string]string)
		},
	}
)

// String returns s, interned.
func String(s string) string {
	m := pool.Get().(map[string]string)
	c, ok := m[s]  // 这里要经过  1.计算字符串 hashcode; 2.hash 查找; 3.字符串内容比较。时间换空间的成本还是挺高的。
	if ok {
		pool.Put(m)
		return c  // 如果字符串池中存在,就置换为字符串池中的对象
	}
	m[s] = s  // 这里不会发生并发问题
	pool.Put(m)
	return s
}

// Bytes returns b converted to a string, interned.
func Bytes(b []byte) string {
	m := pool.Get().(map[string]string)
	c, ok := m[string(b)]  // string(b) 这里有个隐含的知识点:这种情况下编译器不会分配新的字符串对象。
	if ok {
		pool.Put(m)
		return c
	}
	s := string(b)
	m[s] = s
	pool.Put(m)
	return s
}

// todo: 这里还缺乏一个内容:当字符串都来自字符串池的时候,可以提供按照指针比较的方法
// 类似于:
//  isSmae := &str1==&str2 || str1==str2

看完了源码,这个字符串内部化似乎也没有很复杂很高深。或许某个存在大量重复字符串的场景中,我们很能用上这个技术。

最后,ChatGPT 还给了我一段 VictoriaMetrics 中使用 String interning 技术的讲解:

// 以下内容由  ChatGPT 4.0 产生:
VictoriaMetrics采用了字符串内部化技术来优化其时间序列数据库的性能,尤其在处理度量指标的元数据时。这些元数据通常由标签-值对组成,并且在VictoriaMetrics中以字符串的形式表示。下面是VictoriaMetrics中字符串内部化实现的详细信息:

1. 字符串内部化的目的和效果:在VictoriaMetrics中,由于元数据字符串在实践中变化不大,因此在数据收集过程中会产生大量重复。例如,`go_info` 度量指标的元数据包含Go版本的标签-值对。这些版本并不经常变化,但每次从应用程序中收集此度量时,都需要解析其元数据并在内存中分配,直到它被垃圾回收。为了避免多次存储相同的字符串,VictoriaMetrics通过内部化每个独特字符串一次,并在需要时引用它,从而显著节省内存​​​​。

2. 实现方法:在单线程应用中,字符串内部化的一种简单实现方式是使用Go的map类型。但在vmagent这样的多线程应用中,这种方法由于多核系统上访问此映射时可能产生大量争用,因此不太适合。为了在多线程环境下实现内部化,VictoriaMetrics使用了Go标准库中的sync.Map,这是一个线程安全的实现​​。

3. sync.Map的优化用途:sync.Map特别适用于以下两种情况:
  * 当一个给定的键只被写入一次但多次使用时,即缓存命中率高的情况。
  * 当多个goroutine为不同的键集合读取、写入和覆盖条目时,即每个goroutine使用不同的键集​​。

4. 内部化的注意事项:
  * 内存增长问题:随着时间的推移,map会逐渐增长,无限制的内存增长是危险的。为了防止map无限增长,需要定期旋转map,通过删除并重建它,或为键实现某种形式的生存时间(TTL)逻辑。
  * 参数检查:intern函数在处理常规字符串时表现良好,但除非锁定接口,否则可能会有人尝试传递可能破坏函数的内容。例如,在Go中,字节切片是可变的,不适合作为映射中的键使用​​。

5. 内部化的通用建议:在实现字符串内部化时,克隆传递给函数的字符串是一个好主意。这可以帮助消除一些微妙的错误。VictoriaMetrics使用字符串内部化来减少解析度量元数据时的内存使用。这是一种对于读取密集型工作负载效果最佳的强大技术,尤其适用于潜在字符串变体较少的情况​​。

总的来说,VictoriaMetrics通过字符串内部化有效地优化了内存使用和性能,特别是在处理大量重复且不经常变化的度量元数据时。这一技术不仅提高了性能,还降低了对垃圾收集器的负担,是处理大规模时间序列数据的有效方法。

【学到一个新名词】String interning(字符串驻留/字符串内部化)

Have fun. 😃文章来源地址https://www.toymoban.com/news/detail-747825.html

到了这里,关于【学到一个新名词】String interning(字符串驻留/字符串内部化)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • c++:string相关的oj题(把字符串转换成整数、344.反转字符串、387. 字符串中的第一个唯一字符、917. 仅仅反转字母)

    传送门 首先处理空字符串为空的情况() 再处理第一个字符可能为 + - 的情况,直接定一个 flag 初始化为1,遇到 - 就赋值为-1 接下来就利用迭代器进行循环,如果是字符数字就直接使用 ret = ret * 10 + (*it - \\\'0\\\'); 是其他字符,直接return 0;了 传送门 大家学习了c++,可能直接就想

    2024年01月23日
    浏览(27)
  • 「 JavaSE 」String、StringTable、String.intern()详解

    参考鸣谢 深入解析String#intern 美团技术团队 再议String-字符串常量池与String.intern() gcoder_ JVM系列之:String.intern和stringTable 程序那些事 看了这篇文章,我搞懂了StringTable robod 字符串常量池StringTable Mr_cdd Java中的字符串(String)是一种不可变对象,它在许多应用程序中扮演着重要角

    2023年04月08日
    浏览(8)
  • 【JVM】对String::intern()方法深入详解(JDK7及以上)

    String::intern()是一个本地方法,它的作用是如果字符串常量池中 已经包含 一个等于此String对象的字符串,则返回代表池中这个字符串的String对象的引用;否则,会将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。----书上描述 已经包含。。。可能不太

    2024年02月12日
    浏览(11)
  • 面试官:String.intern() 有什么用?和常量池有什么关系?问倒一大片!

    作者:GuoMell 来源:blog.csdn.net/gcoder_/article/details/106644312 在 JAVA 语言中有8中基本类型和一种比较特殊的类型String。这些类型为了使他们在运行过程中速度更快,更节省内存,都提供了一种常量池的概念。常量池就类似一个JAVA系统级别提供的缓存。 8种基本类型的常量池都是系

    2024年02月12日
    浏览(7)
  • Pyecharts绘制3D散点图:把一个图做精细,就能学到好多啦

    版本:2.0.4 官方文档:pyecharts - A Python Echarts Plotting Library built with love.  在如下的设置中,X轴(width)和Y轴(depth)长度相同,Z轴要略矮一点 方法一: 可以将每个样本点的数据设置为4维,前3个维度对应X-Y-Z坐标,第4个维度对应类别,然后通过全局配置项中的视觉映射配置项,t

    2024年01月16日
    浏览(13)
  • 一个计算机专业的学生数据结构这门课学到什么程度才能算学的还不错?

    数据结构之所以重要是因为它处于算法中的基础地位,与解决实际问题关系密切;而之所以不重要是因为课本上能学到的所有实现都已经有人造过轮子了,甚至已经作为很多语言的标准API存在了。 换句话来说,在以后的编码生涯中,你很有可能天天用排序却从来没有写过排序

    2024年02月14日
    浏览(8)
  • Java 字符串数组定义_「string数组」string 数组怎么定义

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站 点击跳转浏览。 String arr[] = new String[10]; //创建一个长度为10的String 类型数组。 String arr[] = {“张三”,“李四”}; 这个是最常用的 String[] arr = new String[10];

    2024年02月15日
    浏览(10)
  • String(字符串)

    java.lang.String类代表字符串,Java程序中的所有字符串文字(例如“abc”)都为此类的对象。 字符串的内容是不会发生改变的,它的对象在创建后不能被更改。 String是Java定义好的一个类。定义在java.lang包中,所以使用的时候不需要导包。 Java程序中的所有字符串文字都被实为此

    2024年02月13日
    浏览(9)
  • String字符串

    直接创建 代码简单,节约内存 使用new创建 有new就会开辟一个新的小空间,地址值不同不会复用浪费空间 案例:用户登录 遍历字符串 统计字符个数 拼接字符串 字符串反转 金额转换 手机号屏蔽 敏感词替换 使用场景:1.字符串拼接。2、字符串反转 常用方法练习 对称字符串

    2024年02月16日
    浏览(16)
  • redis—String字符串

    目录 前言 1.字符串数据类型 2.常见命令 3.典型应用场景 字符串类型是Redis最基础的数据类型,关于字符串需要特别注意: 1)首先Redis中所有的键的类型都是字符串类型,而且其他几种数据结构也都是在字符串类似基础.上构建的,例如列表和集合的 元素类型是字符串类型,所以

    2024年02月02日
    浏览(13)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包