QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

Rubinius 内部细节:线程、对象空间和调试

  • 2007-08-06
  • 本文字数:2399 字

    阅读完需:约 8 分钟

作为 Evan Phoenix 谈 Rubinius:虚拟机内幕面面观的续篇,本文的第二部分将更加深入细节的实现。

Ruby 1.8.x 目前使用用户空间的线程,意味着它无法充分利用多核技术带来的便利,因为操作系统只能感知确定一个线程。Rubinius 目前使用用户空间线程,但是 Evan 同时也考虑了其它的解决方案:

对于 Rubinius 来说,在相同的地址空间中实现多重解释器是件价值不高的事情。编写整个虚拟机的时候就注意到了本地线程安全和可重入机制。这一切来自我在 Sydney 项目的工作经验,这个项目是对 Ruby 1.8.2 版的整理。 你可以轻松地创建两个 Machine(基础的数据结构)并同时将其初始化。它们随后都会保持完全的独立性。唯一要做的工作就是确保两个 Machine 可以合理地调度它们的代码。你甚至可以在两个不同的本地线程中启动两个虚拟机实例并且使其通过通道进行相互通信,这将给你带来一个真正可以利用多处理器特性的 Ruby。

在标准的 Ruby 发布版中,包含简单的调试器,它使用跟踪特性来实现。我们可以通过设置回调函数的方法来使用这个调试器,而这个回调函数在每行新的代码被执行之前被调用。回调函数通过set_trace_func方法来进行注册。(这种方式同样也用于概要分析)。这种方法带来的问题是它较高的系统开销。目前 Ruby 代码每执行一行,意味着要调用跟踪功能并且需要确定是否在这一点上延迟执行。另外也存在其它使用本体扩展的解决方案,就像 ruby-debug 或者 Visual Studio 2005 的 Ruby in Steel 插件所包含的 Cylon 调试器一样。

类似于 Ruby.NET、IronRuby 或是 XRuby 的 Ruby 编译器,恰好把调试信息生成在目标 IL 或字节码中,并且使用各自虚拟机的调试特性。

Rubinius 最近也获得了代码调试的支持,实现了断点的功能,它只有在某个断点命中的时候才会引入额外的性能开销。Evan 对于功能实现这样解释道:

我已经实现了基本的调试设施,这为我们带来了全速的断点(Full Speed Breakpoints)。全速断点意味着在运行期我们不会因为使用调试器而带来任何性能上的损耗了。我认为这是一次巨大的胜利,因为我听说 Ruby 调试器的速度一直以来是个瓶颈。我已经开始在 FSB 的基础之上建立更高级层次的功能,最终,我将可能将其写入类似于 ruby-debug 的机制当中,或是至少在感觉上是类似于 ruby-debug 的机制之中。 从技术角度说,FSB 通过字节码替换进行工作。当断点设置之后,系统使用反射机制查找精确的 CompiledMethod 对象,在这里需要设置调试断点。随后,系统计算字节码,判断断点需要在何处发生,并且使用叫做yield_debugger的奇妙的方式替代目前的指令。当命中这条指令时,系统将控制权交给调试器,这个调试器附属于当前运行的线程上。当这个方法需要继续执行时,旧的指令又被交换回来并且指令指针的值回退 1,并被重新激活。

这个功能运行得很好,因为调试器只是设置为空闲状态,等待运行实际代码的线程与之建立联系。这个功能运行得很好的另外一个原因是 Rubinius 中的方法上下文(Method Contexts)是被作为一等公民对待的。方法上下文和栈框架(Stack Frame)其实是一回事,它描述了方法运行的状态。在 Rubinius 中,你可以从虚拟机中获取系统中任何一个状态的方法上下文。随后就可以通过检查那个对象来发现此刻具体发生的事情。得到方法上下文最简单的方法就是调用“MethodContext.current”,将返回当前运行方法的方法上下文。

随着例如 JVM 和 CLR 这样 Ruby 托管运行时方式的实现,Ruby 的ObjectSpace特性已经出现了一点问题。ObjectSpace 允许对 Ruby 堆中所有可触及的对象进行访问,比方说:

ObjectSpace::each_object(Class){|x|<br></br> p x<br></br>}上述代码将打印当前 Ruby 软件栈中的所有 Class 对象。

JRuby 的开发者 Ola Bini 最近撰写了关于 ObjectSpace 在 JRuby 环境下的性能影响一文。因为 JVM(或者是 CLR)不允许直接访问堆,必须跟踪每一个对象的创建并且保留所有活动对象的清单。Evan 对于 rubinius 中 ObjectSpace 的情况,这样解释道:

我们实际上目前还没有实现它。我们将不会像 JRuby 实现那样有这么多的麻烦,因为我们具有对象存储单元的直接访问能力。Smalltalk语言实现这样的行为主要使用被称作next_object的单一 primitive 实现。当你在大多数对象中调用next_object时,将返回紧随它们之后的一个对象。目前,之后的定义是与具体实现相关的,但是通常的定义是在内存中当前对象的下一个对象。

需要注意到这种方式在任何情况下都不可能保证是无损或者精确的,并且,为了以一种不困扰使用这套接口的开发人员的方式完成,这种方式仍然会有一些性能上的额外开支。这可能令人困惑,因为虚拟机(包括 Rubinius)依赖于这样一个事实:它们可以在内存中重新整理对象,而不会使已经运行的代码产生任何问题。

实际上 Rubinius 这样做是很频繁的,因为垃圾回收器中有一种就是一个复制 - 压缩收集器,因此较新的对象要经常移动。如果你在一个对象上调用next_object,方法返回对象 B,你绝不能指望在下次调用next_object的时候,返回的还是对象 B。

与之相关的一件事是 Rubinius 目前已经完成了将对象的object_id和它在内存中的位置解耦。MRI 的object_id返回对象在内存中的地址,这样之后,我们就可以通过调用ObjectSpace._id2ref,以object_id返回的数值作为参数,从而返回相应对象。在 MRI 中,_id2ref要实现起来相当容易,因为它只需直接从内存的相应位置取得对象就可以了。但是经常用到_id2ref的人知道,有时候你取出来的对象和原先放入的完全不同。这是因为旧的对象已经完成生命周期,而新的对象已经被分配在同一个地方。这虽然没有妨碍人们继续使用_id2ref,但人们应当清楚,_id2ref并不是像人们想象的那样工作的。

无论如何,Rubinius 目前还不支持_id2ref,因为object_id保存的并不是内存地址。我们会找到支持的方式的,但和 JRuby 一样,这可能会成为一个彻底的额外性能开支。

查看英文原文: Evan Phoenix on Rubinius - VM Internals Interview

2007-08-06 03:00887
用户头像

发布了 74 篇内容, 共 13.1 次阅读, 收获喜欢 3 次。

关注

评论

发布
暂无评论
发现更多内容

基于Amazon Machine Learning Bot 的 Named-entity Recognition 快速解决方案

亚马逊云科技 (Amazon Web Services)

AI/ML

从350ms到80ms,打造新零售场景下 iOS 短视频的极致丝滑体验

阿里巴巴终端技术

ios App 短视频 移动开发

在亚马逊云科技Marketplace上的SaaS架构设计——如何支持多产品使用单一账户中心

亚马逊云科技 (Amazon Web Services)

AI/ML

在Amazon SageMaker上快速、灵活构建Amazon TensorFlow模型的在线推理服务

亚马逊云科技 (Amazon Web Services)

AI/ML

Dubbo 框架学习笔记十一

风翱

dubbo 12月日更

利用 Amazon IoT Greengrass 在边缘 DIY 自动浇花系统

亚马逊云科技 (Amazon Web Services)

IoT

无监督欺诈检测|基于iForest异常值检测法的反欺诈研究

索信达控股

算法 模型 反欺诈 iForest 金融交易欺诈检测

“腾源会”成立一周年:助力 40+ 开源项目成长,集结 50+ 位导师大使

腾源会

开源 开源社区 腾源会

虎符上线“圣诞狂欢 没礼不行”活动 邀你瓜分等值66,666 USDT的圣诞礼包

区块链前沿News

区块链 节日 Hoo 虎符交易所 圣诞

Amazon DeepRacer训练日志分析范例与强化学习Reward Function设计

亚马逊云科技 (Amazon Web Services)

AI/ML

2022 全栈开发值得关注的技术产品

开源之巅

ide Web 云服务

数字化石油的开采利器:智能图像识别系统

百度大脑

人工智能

Flink CDC 系列 - 同步 MySQL 分库分表,构建 Iceberg 实时数据湖

Apache Flink

大数据 flink 编程 后端 实时计算

架构实战营第 4 期 -- 模块四作业

烈火干柴烛灭田边残月

架构实战营

直播预告 | 拍乐云与你相约RTSCon2021开发者沙龙

拍乐云Pano

WebRTC RTC

模块七作业

21°Char

优酷弱网平台落地实践

阿里巴巴终端技术

弱网 弱网环境高可用

关于Stream转Map的Duplicate key异常处理

一盐难进

java基础

使用Amazon SageMaker部署CVAT AI自动图像标注系统

亚马逊云科技 (Amazon Web Services)

AI/ML

54 K8S之Prometheus介绍

穿过生命散发芬芳

k8s 28天写作 12月日更

Agora Flat:在线教室的开源初体验

声网

人工智能 开源 flat

CRM 和 C4C product category hierarchy的可编辑性控制逻辑

汪子熙

中间件 CRM 28天写作 ERP 12月日更

Java 中的 xx ≠ null 是什么新语法?

CRMEB

2021年的感悟生活

卢卡多多

盘点2021

【12月日更】深度解析redis分布式锁,那些你不知道的秘密!

小梁编程汇

redis 分布式 RedLock redis分布式锁

百分点认知智能实验室:基于NL2SQL的问答技术和实践

百分点科技技术团队

阿里云混合云重磅亮相中国信通院2021混合云大会

语音信号处理7:语音信号的非线性产生模型

轻口味

28天写作 12月日更

如何将您的自定义容器镜像导入Amazon SageMaker Studio Notebooks

亚马逊云科技 (Amazon Web Services)

AI/ML

手把手教程 | 基于Amazon Kinesis Video Streams实现IP Camera云存项目

亚马逊云科技 (Amazon Web Services)

IoT

网易云音乐广告CTR预估模型演进过程

网易数帆

机器学习 CTR 网易云音乐

Rubinius内部细节:线程、对象空间和调试_Ruby_Werner Schuster_InfoQ精选文章