前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >lldb watch card_table(CLR)的运作模式

lldb watch card_table(CLR)的运作模式

作者头像
江湖评谈
发布2023-10-26 17:58:30
1210
发布2023-10-26 17:58:30
举报
文章被收录于专栏:天下风云天下风云

1.前言 前面两篇(CLR跨代标记内存模型,CLR card_table位移和数组)我们看了下跨代引用的理论知识,本篇来验证下这些说法。

2.概述 示例

代码语言:javascript
复制
 public class Name {
     private string first;
     public Name selfName;
     public Name(string first){
         this.first = first;
     }
 }
 static void Main(string[] args){
     Name n1 = new Name("1111");
     GC.Collect();GC.Collect();
     Name n2 = new Name("3333");
    n1.selfName= n2;C.Collect(0);
 }

老年代的n1.selfName引用了新生代(短暂堆)的n2。

3.观察 命令如下:

代码语言:javascript
复制
b RunMainInternal
c
b PreStubWorker
c
b prestub.cpp:1967
c
br del
n
n
s

此时来到了托管Main入口

代码语言:javascript
复制
(lldb) s
Process 5442 stopped
* thread #1, name = 'clrrun', stop reason = instruction step into
    frame #0: 0x00007fff78d85470
->  0x7fff78d85470: push   rbp
    0x7fff78d85471: sub    rsp, 0x30
    0x7fff78d85475: lea    rbp, [rsp + 0x30]
    0x7fff78d8547a: xor    eax, eax

看下它的栈

代码语言:javascript
复制
(lldb) di -s $pc -c 0x30
->  0x7fff78d85470: push   rbp
    0x7fff78d85471: sub    rsp, 0x30
    0x7fff78d85475: lea    rbp, [rsp + 0x30]
    //中间省略
    0x7fff78d85511: lea    rdi, [rdi + 0x10]
    0x7fff78d85515: mov    rsi, qword ptr [rbp - 0x18]
    0x7fff78d85519: call   0x7ffff730f6e0            ;   JIT_WriteBarrier

在0x7fff78d85519处断

代码语言:javascript
复制
b 0x7fff78d85519
c

可以看到JIT_WriteBarrier,此时n1.selfName==rdi And n2==rsi

代码语言:javascript
复制
(lldb) register read rdi rsi
     rdi = 0x00007fbf6a808b08
     rsi = 0x00007fbf6cc00028

此时的n2的MT(MethodTable)尚未标记存活

代码语言:javascript
复制
(lldb) x/8gx $rsi
0x7fbf6cc00028: 0x00007fff7911c470 0x00007fffe6bff8e0
0x7fbf6cc00038: 0x0000000000000000 0x0000000000000000
0x7fbf6cc00048: 0x0000000000000000 0x0000000000000000
0x7fbf6cc00058: 0x0000000000000000 0x0000000000000000

继续,此处在mark_through_cards_for_segments

代码语言:javascript
复制
(lldb) b gc.cpp:38448
Breakpoint 21: 2 locations.
(lldb) c
limit = min (end, card_address (end_card));

注意看这个limit它就是老年代循环遍历,找出老年代引用的新生代对象,然后对新生代对象进行标记

代码语言:javascript
复制
(lldb) p/x limit
(uint8_t *) $16 = 0x00007fbf6a808b18 ""

limit是遍历循环老年代的结束范围,而n1.selfName的地址是0x00007fbf6a808b08,刚好被包括进来,此时就可以查找到n1.selfName引用的对象,对其进行标记。

此时注意了。请看下面n2的MT

代码语言:javascript
复制
(lldb) x/8gx 0x00007fbf6cc00028
0x7fbf6cc00028: 0x00007fff7911c471 0x00007fffe6bff8e0
0x7fbf6cc00038: 0x0000000000000000 0x0000000000000000
0x7fbf6cc00048: 0x0000000000000000 0x0000000000000000
0x7fbf6cc00058: 0x0000000000000000 0x0000000000000000

它已经被标记存活了,怎么回事?因为n2是根对象,所以在mark_phase的时候已经被标记,此处再次对它进行标记,是因为如果n2不是根对象,mark_phase可能未必标记,此处是为了避免漏掉标记。

4.拾遗 上面似乎没有card_table的操作和内存模型,可以粗略的看下card_table

代码语言:javascript
复制
b find_card
c
Process 5442 stopped
* thread #1, name = 'clrrun', stop reason = step over
    frame #0: 0x00007ffff72f809c libcoreclr.so`WKS::gc_heap::find_card(card_table=0x00007faedb5ff040, card=0x00007fffffffba48, card_word_end=17146007553, end_card=0x00007fffffffbab0) at gc.cpp:37953:30
   37950  
   37951      // Find the first card which is set
   37952      last_card_word = &card_table [card_word (card)];
-> 37953      bit_position = card_bit (card);

它里面跟之前描述基本无差。另外的内存模型可以通过set_card推导,Linux和windows似乎不太一样,还需要研究。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 江湖评谈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档