2015-11-12 5 views
5

私はdata.table::addressまたは.Internal(address())を使用してメモリ内のさまざまなオブジェクトを追跡しようとしましたが、一部のオブジェクトは毎回同じアドレスを返すことに気付きました。ここで何が起こっているのですか?他のメモリアドレスが変更されている間に、一部のメモリアドレスが一定の理由で報告されるのはなぜですか?

私はリスト(data.tables、data.framesなど)のようなオブジェクトのアドレスは(これらの関数によって報告されているように)一定であることに気付きましたが、アドレスを[でリストに報告しようとするとaddress(lst[1])私は毎回異なる結果を得ます。一方、lst[[1]]は同じ値を返し、address(pi)のような定数のアドレスは一定のままですが、address(1)はvolatileです。なぜこうなった?

## Create some data.tables of different sizes and plot the addresses 
library(data.table) 
par(mfrow = c(2,2)) 
for (i in 2:5) { 
    dat <- data.table(a=1:10^i) 
    ## Constants 
    addr1 <- address(dat) 
    addr2 <- address(dat[[1]]) 
    addr3 <- address(dat$a) # same as addr2 
    ## Vary 
    addrs <- replicate(5000, address(dat[1])) 
    plot(density(as.integer(as.hexmode(addrs))), main=sprintf("N: %g", nrow(dat))) 
    abline(v=as.integer(as.hexmode(c(addr1, addr2, addr3))), col=1:3, lwd=2, lty=1:3) 
    legend("topleft", c("dat", "dat[[1]]", "dat$a"), col=1:3, lwd=2, lty=1:3) 
} 

ここでは、私はさまざまなサイズのdata.tablesで話しているのいくつかの例です。それらは、address(dat[1])(整数に変換された)の結果の密度であり、その行はdata.tableの定数アドレスに対応しています。

enter image description here

+3

私は完全な答えはありませんが(Cコードを勉強する必要があります)、いくつかの提案があります。 '[['と '$'は単一のリスト要素を返します。しかし、 '['は1つ以上のリスト要素を含むリストを返します。つまり、これらの要素がコピーされます。特定の状況でこれらのコピーを避ける最適化が可能かもしれませんが、そのトピックは私の給与等級以上です。 – Roland

+1

スカラーインデキシングリストを '' ["" '[[" 'と違うオブジェクトをコピーするか、どうしたのですか? '' [リスト "のようなオブジェクトだけが返される新しいSEXPを割り当てていないようで、サブセットを抽出するコピーは行われません。また、作成された変数(「pi」など)とは異なり、「1」と入力すると毎回新しいオブジェクトが作成されます。 –

+0

@時間:値 "a"を持つ2つの変数を作成する場合、STRSXPがあります。キャッシュにはアクセスできないCHARSXPが含まれます。例:straddr = inline :: cfunction(sig = c(x = "character")、body = 'Rprintf( "%p \\ n"、x);') '; (STRING_ELT(x、0)); ') 'charaddr =インライン:: cfunction(sig = c(x ="文字 ")、body =' Rprintf("%p \\ n " 'x =" a "; y = "a"。 'straddr(x); straddr(y); charaddr(x); charaddr(y) '。 –

答えて

3

まず第一に、私はあなたの結果を再現することができますので、私は調査のビットを行なったし、いくつかのコードを潜りました。

あなたが実際にdata[[1]]listまたはdat$aから作られたスライスを作成しているdat[1]を使用してdatの最初のメンバーにアクセスします。スライスを取るために、Rはまずリストをコピーして、あなたが望むスライスを返します。

ので - 基本的には - あなたは、索引付けのため[]構文は、任意のメモリ位置になりますdat$aのコピーであるdatの最初の要素を含むスライスを返すので、あなたが見るものを参照してください。

[[]]構文は、あなたのdata.tabledata.frameの列であるため、そのアドレスは不変である(あるいはあなたがそのリストのメンバーを変更するまで、少なくともそれはある)、実際のリストへの参照を返します。

もちろん、dat[1] = 6などを実行すると、データ構造内のリストの値が変更されるため、混乱する可能性があります。ただし、変更前と変更後にaddress(dat[[1]])を見ると、実際に参照が異なるリスト(コピー)になっていることに気づくでしょう。 data.frame(よりむしろdata.table)のソースコードを見ると

> dat <- data.table(a=1:10000) 
> dat 
      a 
    1:  1 
    2:  2 
    3:  3 
    4:  4 
    5:  5 
    ---  
9996: 9996 
9997: 9997 
9998: 9998 
9999: 9999 
10000: 10000 
> address(dat[[1]]) 
[1] "000000000CF389D8" 
> address(dat[[1]]) 
[1] "000000000CF389D8" 
> dat[1] = 100 
> address(dat[[1]]) 
[1] "000000000D035B38" 
> dat 
      a 
    1: 100 
    2:  2 
    3:  3 
    4:  4 
    5:  5 
    ---  
9996: 9996 
9997: 9997 
9998: 9998 
9999: 9999 
10000: 10000 
> 

、スライスインデクシング([]is hereを行うコード、直接インデキシング一方([[]]is here。後者は簡単で長いストーリーを短縮することができます。前者はコピーを返します。スライスを直接変更する場合(例:dat[1] = 5)、logic hereがあり、データフレームが更新されたコピーを参照するように処理します。

関連する問題