2

在 SBCL 中获取对象位长

 2 years ago
source link: https://www.ttalk.im/2019/08/how-to-get-object-size-in-sbcl.html?amp%3Butm_medium=Atom
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在 SBCL 中获取对象位长

由 David Gao 发布于: 2019-08-29

编程, Lisp, Common Lisp, 便贴

因为字符串编码问题,引发笔者对SBCL的内存分配进行一次简单的探究。

近期大量语言发生了突飞猛进的发展,很多古代语言从单纯的支持ASCII演变成支持utf8。 但是utf8并非是一个有效字符存储方案,所以在Erlang中一个中文字符会被定义为16位,也 就是我们常说的utf16,从而达到高效但非节约的存储。那么自己常用的Common Lisp中,一 个中文字符又是会被定义为多少位呢?

首先要实现下面这函数

(defun get-object-size/octets (object)
  (sb-sys:without-gcing
    (nth-value 2 (sb-vm::reconstitute-object
                  (ash ;; 因为返回了一个fixnum对象的lispobj,因此需要进行这一步的处理
                        (logandc1 sb-vm:lowtag-mask (sb-kernel:get-lisp-obj-address object)) ;; 掩码掩掉最后nbit,得到lispobj真正地址,n取决于平台,x64是4
                       (- sb-vm:n-fixnum-tag-bits))))))

为什么会有这个函数呢,因为lisp在创建对象的时候和Erlang是一致的,都会将指针的空位 设置为标签掩码。

接着我们测试一个中文字符

(defvar *c* "中")
(get-object-size/octets *c*) ;; 32bit

但是查阅了SBCL的代码的时候,发现

(def!constant sb!xc:char-code-limit #!-sb-unicode 256 #!+sb-unicode #x110000
  "the upper exclusive bound on values produced by CHAR-CODE")

也就是说,SBCL会使用一个32bit的位长来表示一个utf16的字符,具体可以参阅Memory Layout

从这个测试中可以发现,绝大部份古代语言真对宽字符会直接处理成utf16,而不是utf8。 当然也有一些特例,例如OCaml,一个字符依然是8bits,对宽字符会处理成utf8。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK