unless’s blog

日々のちょっとした技術的なことの羅列

GCと循環参照について

いままでぜんぜん気にしていなかったけどPerlGCはリファレンスカウント方式らしい

なのでオブジェクトへの参照が作られるたびにリファレンスカウントを増やしていって
オブジェクトへの参照が破棄されたタイミングでリファレンスカウントが減ることになる
そしてリファレンスカウントが0になったタイミングでそのオブジェクトは開放される

$ perl -MDevel::Peek -e 'my $foo; Dump $foo; my $bar = \$foo; Dump $foo; undef $bar; Dump $foo;'
SV = NULL(0x0) at 0xa96c18
  REFCNT = 1
  FLAGS = ()
SV = NULL(0x0) at 0xa96c18
  REFCNT = 2
  FLAGS = ()
SV = NULL(0x0) at 0xa96c18
  REFCNT = 1
  FLAGS = ()

REFCNT がリファレンスカウント数

また、スコープを切ってあげるとオブジェクトへの参照が破棄されてリファレンスカウントが減る模様

$ perl -MDevel::Peek -e 'my $foo; Dump $foo; {my $bar = \$foo; Dump $foo;} Dump $foo;'
SV = NULL(0x0) at 0x1dc6c18
  REFCNT = 1
  FLAGS = ()
SV = NULL(0x0) at 0x1dc6c18
  REFCNT = 2
  FLAGS = ()
SV = NULL(0x0) at 0x1dc6c18
  REFCNT = 1
  FLAGS = ()

なのでわりと簡単に循環参照を作るのことができててしまう

SV = NULL(0x0) at 0x24c9c60
  REFCNT = 1
  FLAGS = ()
SV = IV(0x24c9c50) at 0x24c9c60
  REFCNT = 2
  FLAGS = (ROK)
  RV = 0x24c9c60
  SV = IV(0x24c9c50) at 0x24c9c60
    REFCNT = 2
    FLAGS = (ROK)
    RV = 0x24c9c60
    SV = IV(0x24c9c50) at 0x24c9c60
      REFCNT = 2
      FLAGS = (ROK)
      RV = 0x24c9c60
      SV = IV(0x24c9c50) at 0x24c9c60
        REFCNT = 2
        FLAGS = (ROK)
        RV = 0x24c9c60
        SV = IV(0x24c9c50) at 0x24c9c60
          REFCNT = 2
          FLAGS = (ROK)
          RV = 0x24c9c60
Cycle (1):
                               $$A => \$A

省メモリかつオブジェクトの破棄するタイミングを完璧にコントロールできるが
循環参照には気をつけないとメモリリークを起こしてしまう可能性もあるので
今後は意識しながらプログラミングしていこうと思った