写点什么

JRuby 1.1RC2 发布,内存需求降低

2008 年 2 月 26 日

JRuby 1.1 的第2 候选发行版 (RC2) 已经发布了, 它相对 RC1 版做了很大改进: > - 在 JRuby 1.1RC1 的基础上解决了 260 个问题

- 大规模 IO 的重构
- 在内存方面对 JIT 编译的方法的改进:

  • 控制 JIT 编译出的方法总数
  • 支持一种用于各个运行时的 JIT 缓存来归还 permgen
  • 减少了生成方法的代码长度(减少 50-70%)

仅次于 Oniguruma Regex 引擎的 Java 移植,JRuby 1.1 相对于JRuby 1.0 最显著的性能改进就是Just In Time ( JIT) 编译器的引入,它用来把 Ruby 代码编译成JVM 字节代码。但是,它也得面对JVM 语言实现需要对付的问题。采用在 JVM 中管理字节代码的方式给 JRuby 的 JIT 带来了一些问题。在 JVM 中,类是字节代码最小的可装载单位——因此,如果一个 Ruby 方法被 JIT 编译,生成的代码就被放入一个新类的方法体中,然后被装载。然而,这正是一个潜在的问题源头和内存泄露者:字节代码被装入PermGen,一个垃圾收集段,它默认很小,通常是 64MB。Nick Sieger 说明了它会很快被 JIT 编译的 Ruby 方法填满:

例 如一个不算太简单的 Rails 应用程序,它充分使用 Ruby 标准库,还用了一大堆插件,由 JRuby 编译的方法轻易地超过了 10,000 个。倘若一个 JRuby 方法类的平均开销大约是 8K(当然根据方法的长度有所不同),他们就会占用 80 兆的 permgen 空间。(而 JVM 的 permgen 空间大小默 认是 64 兆字节,因此我们已经超过了这个限制)。
[…]
如果你在一个应用程序服务器上部署 4 个 Rails 程序,每个使用 4 个活动运行时的话,你就得面对 1.2G 字节的 permgen 空间需求!(一般来说,在 Java 应用程序服务器上运行多个程序很常见,但是要运行多个 Rails 程序可能需要重新考虑一下。)

这是个非常实际的问题——PermGen 表现地很像常规的 Java 堆:它有固定的大小,一旦 PermGen 满了,就会抛出OutOfMemory异常,并最终导致 JVM 崩溃。 Nick Sieger 解释了 RC2 中对这个问题的几个解决方案:

由于这个问题带来的消耗太大,在 JRuby 1.1RC1 发布不久,我们就采用了近乎激烈的手段把每个运行时都会进行 JIT 编译的方法的数量限制到 2048 个。但是过了不久就发现,很明显,即使使用 基于阈值的方法,JRuby 还是浪费了大量的 permgen 空间,里面堆满了编译后的方法的重复拷贝。因此,在 1.1RC2 中,我们引入了一种 JIT 缓 存,它可以在多个运行时中共享。

这个问题的解决方案已经有了,就像 .NET 平台上的动态方法那样。不是把Ruby 方法编译成Java 类的单一方法体,而是把字节代码存储在一个方法对象里——注意,是对象。这些动态方法表现得和常规对象一样,当它们不再被使用的时候,就会被回收。这种方法还用于减少大量的其他开销, John Rose 解释道

动态语言实现的一个麻烦点是动态管理代码。开发者把注意力放在方法体和方法体与一些预期的调用序列之间的连接的时候,JVM 需要大量上下文细节来把代码放到适当的位置。这些细节包括:

  • 方法名
  • 封装类名
  • 与其他命名实体相关的各种访问限制
  • 类装载器和保护域
  • 连接和初始化状态
  • 类分层结构的安置(即使类从来没有实例化)

这 些细节给开发者的任务添了不少麻烦,而且他们经常导致各方面的执行开销。因为一个命名的类(和类装载器)必须被精确定义,并在之后可以通过它的名字来回收 (通过 Class.forName)。JVM 必须把每一个新定义的类连接到它的定义类装载器和一个称为系统词典的数据结构,用于在以后处理连接请求。建立 连接需要一定的时间,尤其是当它们必须获得各种系统锁时。这些都令 GC 收集不用的代码变得很困难。

当然,像.NET 中的动态方法这样的特色在 JVM 中没有实现。相关的研究正在 Da Vinci Machine 项目中进行,现在已经实现了原型,但是这样的特色要等到下一个 Java 版本发布时才能看到。查看原文: JRuby 1.1RC2 released with reduced memory requirements

2008 年 2 月 26 日 03:11308
用户头像

发布了 33 篇内容, 共 34349 次阅读, 收获喜欢 0 次。

关注

评论

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

开始每周写作计划

M1racle

一个平凡程序员的年度总结

小智

程序员 人生

业务代码的救星——Java 对象转换框架 MapStruct 妙用

周三不加班

MapStruct 对象转换

对你来说,阅读是另一种生活的方式吗?

叶小鍵

DDD 实践手册(4. Aggregate — 聚合)

Joshua

设计模式 领域驱动设计 架构模式

翻译和产品本地化的区别是什么?

葛仲君

翻译 本地化 全球化 产品开发

centos7 maven私服自动启动

kcnf

写字工具更新史

Bonaparte

学习 读书笔记

习惯与惯性

伯薇

个人成长 习惯 习惯养成 提升能力

读懂才会用 : Redis的多线程

小眼睛聊技术

Java redis 学习 程序员 编程语言 后端

Clickhouse 性能测试

久吾尔岂

MySQL中 int(11)和 int(10) 到底有没有区别?

周三不加班

MySQL 字符宽度 数据库数据类型

机会是留给不停寻找他们的人,而不是原地等待的人

非著名程序员

程序员 提升认知 机会 行动派

当我们谈到ThreadLocal的时候,我们在谈什么?

Jason

Java 多线程 ThreadLocal

内存对齐

helloworld

c c++ C#

关于GDB你需要知道的技巧

helloworld

c c++ C#

如何对Code Review的评论进行分级

宝玉

代码审查 Code Review

重新认识Go语言中的slice

麻瓜镇

golang

如何利用数据异构实现多级缓存或者数据迁移

松花皮蛋me

缓存 分布式 分库分表

面试指南 | 终于要跟大家见面了,我有点紧张。

Apache Flink

大数据 flink 流计算 实时计算 大数据处理

各大公司面试题分类整理

是小毛吖

后端 面试题

Service Worker in Action

xgqfrms

Service Worker Web Worker

婚姻就是合伙开公司,各自做好自己的工作很重要

鼎玉谷

管理 婚姻 公司 付出 人情

《TCP/IP详解》概述

网瘾少年SEC

TCP 网络协议 IP

Redis 6.0 新特性-多线程连环13问!

牧码哥

redis 多线程 io

C++线程池的实现

helloworld

c++ C# 线程池

C++定时器的实现

helloworld

c c++ C#

浅谈SpringCloud之服务注册中心Eureka

北漂码农有话说

金融「中台」十宗罪

fino星君

中台 企业中台 业务中台

写作的意义到底是什么

七镜花园-董一凡

写作

笔记:《如何系统思考》之如何做到系统思考

wiflish

思维方式

如何打造一支有战斗力的技术团队?

如何打造一支有战斗力的技术团队?

JRuby 1.1RC2发布,内存需求降低-InfoQ