guk*_*off 7 python string garbage-collection
Python中的字符串是不可变的,并且支持缓冲区接口.因此,在使用切片或split()方法时,不返回新字符串,而是返回旧字符串的部分是有效的.但是,据我所知,每次都会构造新的字符串对象.为什么会这样?我看到的唯一原因是它可以使垃圾收集变得更加困难.
是的:在常规的语言中,内存开销是线性的,并不明显:复制速度很快,我相信,分配也是如此.但是在python中做太多事情只是说它不值得努力!
编辑:
似乎使用这种方式会使内存管理变得更加复杂.在这种情况下,只使用1/5的任意字符串,并且我们无法解除分配整个字符串,这是一个简单的例子.我们可以改进内存分配器,因此它可以部分地释放字符串,但它可能主要是反驳.如果内存使用非常重要,那么无论如何都可以使用缓冲区或内存视图模拟所有标准函数.是的,代码不会那么简洁,但我们必须放弃一些东西才能得到一些东西.
底层字符串表示形式是以null 结尾的,即使它跟踪长度,因此您不能拥有引用不是后缀的子字符串的字符串对象。这已经限制了您的提案的有用性,因为它会增加很多复杂性来以不同的方式处理足够和非足够(并且放弃空终止字符串会带来其他后果)。
允许引用字符串的子字符串意味着使垃圾收集和字符串处理变得复杂。对于每个字符串,您必须跟踪有多少对象引用每个字符或每个索引范围。struct这意味着字符串对象以及任何处理它们的操作都会变得复杂,这意味着速度可能会变慢。
再加上从 python3 开始的字符串有 3 种不同的内部表示,事情会变得太混乱而难以维护,而且你的提案可能没有提供足够的好处来被接受。
这种“优化”的另一个问题是当您想要释放“大字符串”时:
a = "Some string" * 10 ** 7
b = a[10000]
del a
Run Code Online (Sandbox Code Playgroud)
b执行此操作后,您将获得阻止释放的子字符串a(一个巨大的字符串)。当然你可以复制小字符串,但是如果b = a[:10000](或另一个大数字)呢?10000 个字符看起来像一个大字符串,应该使用优化来避免复制,但它阻止释放兆字节的数据。垃圾收集器必须不断检查是否值得释放大字符串对象并进行复制,并且所有这些操作必须尽可能快,否则最终会降低时间性能。
99% 的情况下,程序中使用的字符串都是“小”(最多 10k 个字符),因此复制速度非常快,而您建议的优化对于非常大的字符串开始变得有效(例如,从巨大的文本中获取大小为 100k 的子字符串) )并且对于非常小的字符串要慢得多,这是常见的情况,即应该优化的情况。
如果您认为重要,那么您可以自由地提出 PEP,展示实现以及您的提案的速度/内存使用量的最终变化。如果它确实值得付出努力,它可能会包含在 python 的未来版本中。