#define LJ_TSTR (~4u)
static long loop_gc_obj(u32 index, callback_ctx *ctx)
{
int res;
GCRef p = ctx->p;
// read o
GCobj *o;
res = bpf_probe_read(&o, sizeof(o), (GCobj *)(p.gcptr64));
if (res != 0) {
return 1;
}
// read gct type
uint8_t gct;
res = bpf_probe_read(&gct, sizeof(gct), &(o->gch.gct));
if (res != 0) {
return 1;
}
int gct_size = luajit_objlen(o, gct);
// next gco
res = bpf_probe_read(&p, sizeof(p), &(o->gch.nextgc));
if (res != 0) {
return 1;
}
ctx->p = p;
return 0;
}
SEC("kprobe/handle_entry_lua")
int handle_entry_lua(struct pt_regs *ctx)
{
// ...
GCRef p;
bpf_probe_read(&p, sizeof(p), &(g->gc.root));
callback_ctx loop_ctx = {
.p = p,
};
bpf_loop(1 << 23, loop_gc_obj, &loop_ctx, 0);
return 0;
}
+--------------------------------------------------------------------+
| Gct Type Name Count Sum Max Min |
+--------------------------------------------------------------------+
| 5 upvalue 183 8784 48 48 |
| 6 thread 1 0 0 0 |
| 7 proto 77 30043 1868 120 |
| 8 function 215 11984 160 40 |
| 9 trace 8 0 0 0 |
| 10 cdata 203 0 0 0 |
| 11 table 72 21568 3136 64 |
| 12 udata 2 144 80 64 |
+--------------------------------------------------------------------+
如上面代码所示,我正在使用eBPF分析luajit GC对象的内存使用情况,但是我发现无论我如何创建String类型对象,都无法获取string类型gct的对象。
local str1 = "Hello, "
local str2 = "World!"
local result = str1 .. str2
字符串对象不会放入主对象链表中。相反,它们由存储在 global_State 中的内部字符串哈希表(StrInternState::tab)进行跟踪,当一个槽有多个值时,nextgc 字段也用于在哈希表中进行链接。
您可以使用从我制作的用于创建 GC 堆快照的系统中获取的这段代码作为如何遍历表的指南
int collect_strings(global_State *g)
{
uint32_t count = 0;
for (MSize i = 0; i <= g->str.mask; i++) {
GCobj *o = (GCobj *)(gcrefu(g->str.tab[i]) & ~(uintptr_t)1);
/* Walk a string hash chain. */
for (; o != NULL; o = gcref(o->gch.nextgc)) {
if (((uintptr_t)o) <= 1) {
break;
}
dostuff(o);
count++;
}
}
return count;
}