Ruby,不可变的整数和未使用的对象

问题描述

a = 1
a += 1
=> 2

原始对象1现在未使用,这不是很有效。为什么整数在ruby中是不可变的?我看过stackoverflow,但找不到任何解释。

解决方法

整数和所有Numerics都是不可变的,因此每个整数中只有一个。我们可以通过检查他们的#object_id来看到这一点。

2.6.4 :001 > a = 1
 => 1 
2.6.4 :002 > a.object_id
 => 3 
2.6.4 :003 > 1.object_id
 => 3 
2.6.4 :004 > b = 1
 => 1 
2.6.4 :005 > b.object_id
 => 3 

此行为也以数字记录。

其他核心数字类(“数字”除外)(例如Integer)被实现为立即数,这意味着每个Integer是始终由值传递的单个不可变对象。例如,只能有一个整数1的实例。 Ruby通过防止实例化来确保这一点。如果尝试复制,则返回相同的实例。

每个Integer具有单个不变对象可以节省正常使用的内存,因此您将大量使用1。共享相同的1的每个人都节省了大量内存,但这意味着它必须是不可变的,否则添加到一个对象将更改其他对象和that would be bad

不必一遍又一遍地不断地取消分配和分配同一Integer,这样会更快,并减少了内存碎片。如果它们确实没有使用,请Ruby will garbage collect them。 Ruby的垃圾回收在不断改进,可以通过许多环境变量进行调整。

这也简化了它们的实现,并使它们性能更高。不可变的对象可以缓存任何计算,确信缓存将永远不需要无效。

,

为什么红宝石中的整数不可变?我看过stackoverflow,但找不到任何解释。

让我们假设Integer易变的:

1 << 1
1 + 1
#=> 4

我猜测您找不到解释的原因是,大多数人认为将1的值更改为1之外的任何其他功能是不言而喻的,这会导致绝对疯狂的维护噩梦。

,

考虑突变整数的能力以及这对ruby程序员的要求。这将使他们在改变语言观察世界的方式上有太多的力量。整数对象是内存中的一连串二进制数字,如果将该对象加1,它仍然是一个吗?不。这就是为什么Ruby使用变量指向对象而不是对其进行突变的原因。

不可变的整数从长远来看可以节省消耗。我认为您在这里提出的疑问是,ruby决定使原始对象不可变并将其存储在内存中而不是对其进行更改,这会增加内存消耗吗?好吧,a不是全局变量,最终应该由垃圾回收清除。 Ruby使用DRY原则进行对象分配,因此保留对象而不是一遍又一遍地创建它们是有意义的。如果您有更多的对象而不是ruby可以容纳到内存中,则它必须分配更多的内存,这在OS上是昂贵的,但是您的代码应该对此有所了解。当分配过多时,Ruby会释放内存。 Ruby对象存储在Ruby object heap中,而不是垃圾收集器经常清理的malloc heap中。

如果整数是可变的,那么修改在应用程序中其他地方使用的变量将导致难以修复的回归,并在Web应用程序中引起很多问题。关于保留和性能方面的问题,请看以下示例:

require 'newrelic_rpm'

a = 0
loop do
  a += 1
  if a % 10_000 = 0
    p a
    p  NewRelic::Agent::Samplers::MemorySampler.new.sampler.get_sample
  end
end

观察“保留”了多少个对象以及该进程消耗了多少内存。现在,考虑一下在一个现实世界的程序中要保留多少个对象,并考虑内存消耗是否是一个现实问题。如果您确实遇到了此问题(我认为不会遇到此问题),请将其视为改善代码的通知。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...