设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 2576|回复: 6
打印 上一主题 下一主题

[讨论] Ruby 1.8(VX) &1.9(ACE) 的 String 的 object_id 与内存

[复制链接]

Lv3.寻梦者

弓箭手?剑兰

梦石
0
星屑
4819
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
跳转到指定楼层
1
发表于 2012-1-15 11:43:57 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
首先,
为了取得某个 String 的指针,我在 VX/RGE/XP 下写这个脚本:
  1. RtlMoveMemory_pi = Win32API.new("kernel32", "RtlMoveMemory", "pii", "i")
  2. ab = "abcdefg"
  3. address = "xxxx"
  4. RtlMoveMemory_pi.call(address, ab.object_id * 2 + 12, address.size)
  5. address = address.unpack("L")[0]   # 这个就是内存位置的开头
  6. buff = " " * ab.size               # 将成为 "abcdefg" 的复制本
  7. RtlMoveMemory_pi.call(buff, address, ab.size)
  8. p buff
复制代码
那时候的 object_id * 2 + 12 是"撞"出来的,所以我没有查到 Ruby 的内存结构。
ACE 的时候,发现不管用,而且出现全"\0"和全"?",并且程序有一定几率死掉(似乎因为读取内存不属于程序)。

问题是结构和 object_id 有什么分别?

Lv1.梦旅人

梦石
0
星屑
50
在线时间
26 小时
注册时间
2011-1-22
帖子
10
2
发表于 2012-1-15 18:04:29 | 只看该作者
顶起来,果然没有人讨论这个么T.T....
回复 支持 反对

使用道具 举报

Lv1.梦旅人

炎发灼眼的讨伐者

梦石
0
星屑
50
在线时间
1707 小时
注册时间
2007-8-4
帖子
904
3
发表于 2012-1-15 18:17:16 | 只看该作者
class String
  
  Lstrcpyn = Win32API.new("kernel32", "lstrcpyn", "ppi", "l")
  
  def addr
    return Lstrcpyn.call(self, 0.chr, 0)
  end

end
用这个取字符串地址试试(objectid 没看……额
RMXP&RMVX通用Web化完成- -|||
回复 支持 反对

使用道具 举报

Lv3.寻梦者

弓箭手?剑兰

梦石
0
星屑
4819
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
4
 楼主| 发表于 2012-1-15 18:36:15 | 只看该作者
灼眼的夏娜 发表于 2012-1-15 18:17
class String
  
  Lstrcpyn = Win32API.new("kernel32", "lstrcpyn", "ppi", "l")

呵。完全忘记了 Win32API 有 C/C++ 的字符串函数。
嗯...什巧妙的,但似乎违背了这个函数的意义- -||。结果(结论):
VX(Ruby 1.8):addr = RtlMoveMemory(object_id * 2 + 12, 4)
ACE(Ruby 1.9):addr = object_id * 2 + 8
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
163 小时
注册时间
2011-11-12
帖子
56
5
发表于 2012-1-16 00:57:27 | 只看该作者
這個可以查 1.9 的 ruby.h,裏面有 RString 的定義(<-- 在頭文件裏進行定義的習慣不好)。
  1. struct RString {
  2.     struct RBasic basic;
  3.     union {
  4.         struct {
  5.             long len;
  6.             char *ptr;
  7.             union {
  8.                 long capa;
  9.                 VALUE shared;
  10.             } aux;
  11.         } heap;
  12.         char ary[RSTRING_EMBED_LEN_MAX + 1];
  13.     } as;
  14. };
复制代码
下面還有一個返回指針的宏:
  1. #define RSTRING_PTR(str) \
  2.     (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
  3.      RSTRING(str)->as.ary : \
  4.      RSTRING(str)->as.heap.ptr)
复制代码
[/code]
在 string.c 裏可以看到 Ruby 1.9 是如何分配新字符串的,裏面有這麼一段:
  1.     if (len > RSTRING_EMBED_LEN_MAX) {
  2.         RSTRING(str)->as.heap.aux.capa = len;
  3.         RSTRING(str)->as.heap.ptr = ALLOC_N(char,len+1);
  4.         STR_SET_NOEMBED(str);
  5.     }
复制代码
可見 Ruby 1.9 對較短的字符串作了優化,當字符串長度小於等於 RSTRING_EMBED_LEN_MAX 的時候就直接把字符串嵌入到 RString 這個對象結構裏,而不是重新在堆裏分配內存,避免了頻繁 malloc 小內存塊帶來的內存碎片開銷。當把字符串嵌入 RString 裏的時候,那些堆的信息就不需要了;當在堆中分配字符串的時候,用於嵌入字符串的地址 RString#as.ary 就不需要了,所以才有外部的那個 union。

  1. #define RSTRING_EMBED_LEN_MAX ((int)((sizeof(VALUE)*3)/sizeof(char)-1))
复制代码
這個定義在 Win32 環境下應該總是展開為 11。你不妨試試長一點的字串。

点评

嗯,请问哪里可以查到 ruby.h 和其他的 C/C++ 档案呢?  发表于 2012-1-29 09:51
回复 支持 反对

使用道具 举报

Lv2.观梦者

梦石
0
星屑
260
在线时间
1373 小时
注册时间
2005-10-16
帖子
5113

贵宾

6
发表于 2012-1-21 22:53:31 | 只看该作者
在ACE里 ["a","b","c"].to_s 会得到一个很囧的结果……
我只个搬答案的
叔叔我已经当爹了~
婚后闪人了……
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
163 小时
注册时间
2011-11-12
帖子
56
7
发表于 2012-1-21 23:20:57 | 只看该作者
亿万星辰 发表于 2012-1-21 22:53
在ACE里 ["a","b","c"].to_s 会得到一个很囧的结果……

1.9 行為改變了:
enum.to_s → str
Returns a string representation of enum. (Prior to Ruby 1.9, this representation was the same as enum.join. Now it is the array as a literal.)
[ 1, 3, 5, 7, 9 ].to_s # => "[1, 3, 5, 7, 9]
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-4-26 05:49

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表