동일한 벡터에 대한 두 개의 참조가 벡터의 각 요소에 대해 서로 다른 메모리 주소를 반환하는 이유는 무엇입니까?


9

저는 R을 배우고 있으며 현재이 책을 읽고 있습니다. 개념을 이해하기 위해 다음 테스트를 실행하여 매우 혼란 스러웠으며 명확하게 설명해 주시면 감사하겠습니다. 다음은 터미널에서 R 셸에서 직접 실행 한 테스트입니다 (RStudio 또는 Emacs ESS를 사용하지 않음).

> library(lobstr)
>
> x <- c(1500,2400,8800)
> y <- x
> ### So the following two lines must return the same memory address
> obj_addr(x)
[1] "0xb23bc50"
> obj_addr(y)
[1] "0xb23bc50"
> ### So as I expected, indeed both x and y point to the same memory 
> ### location: 0xb23bc50
>
>
>
> ### Now let's check that each element can be referenced by the same
> ### memory address either by using x or y
> x[1]
[1] 1500
> y[1]
[1] 1500
> obj_addr(x[1])
[1] "0xc194858"
> obj_addr(y[1])
[1] "0xc17db88"
> ### And here is exactly what I don't understand: x and y point 
> ### to the same memory address, so the same must be true for 
> ### x[1] and y[1]. So how come I obtain two different memory
> ### addresses for the same element of the same vector?
>
>
>
> x[2]
[1] 2400
> y[2]
[1] 2400
> obj_addr(x[2])
[1] "0xc15eca0"
> obj_addr(y[2])
[1] "0xc145d30"
> ### Same problem!
>
>
>
> x[3]
[1] 8800
> y[3]
[1] 8800
> obj_addr(x[3])
[1] "0xc10e9b0"
> obj_addr(y[3])
[1] "0xc0f78e8"
> ### Again the same problem: different memory addresses

내 실수가 어디인지,이 문제에서 내가 잘못 이해 한 것이 무엇인지 말해 줄 수 있습니까?


1
나는 R을 모르지만 다른 언어에서는 가치와 참조 유형이 있습니다. 정수가 C ++ 또는 C #에서와 같이 값 유형이면 할당이 새 정수를 작성합니다. 따라서 모든 정수에는 고유 한 주소가 있습니다.
— 호스텔

1
실제로 obj_addr(x[1])두 번 실행하더라도 새로운 정수마다 자체 주소가 있으므로 다른 결과를 제공해야합니다.
— Bas

@Bas 나는 당신이 언급 한 것을 테스트했다. 즉, 연속적으로 obj_addr (x [1])을 실행하고 실제로 그렇게하면 R은 매번 다른 결과 (다른 메모리 주소)를 반환한다. 그러나 왜 그런지 이해하지 못합니다. 왜냐하면 나에게 아무것도 할당하지 않았기 때문에 새 객체를 만들지 않습니다 (물론 R에서 객체를 변경할 수 없으므로 새로운 주소가 있음). 나를 위해 obj_addr (x [1])은 이미 기존 객체를 읽는 중임을 의미합니다.
— user17911

답변:


5

모든 R 객체는 C (포인터라고 불림 SEXP) "다중 객체"( struct)입니다. 여기에는 lengthR 객체에 대한 정보 (R이 작동해야하는 참조 수 , 예를 들어 객체를 복사 할시기 등을 알기 위해 필요한 정보 등)와 액세스 할 수있는 R 객체의 실제 데이터가 포함됩니다.

lobstr::obj_addr아마, SEXP가리키는 메모리 주소를 반환합니다 . 메모리의 해당 부분에는 R 개체 의 정보 와 데이터 가 모두 들어 있습니다 . R 환경 내에서 우리는 각 R 객체에있는 실제 데이터의 (포인터를 가리키는) 메모리에 액세스 할 필요가 없습니다.

Adam이 답변에서 언급 한 것처럼이 함수 는 C 객체에 포함 된 데이터의 n 번째 요소를 새 C 객체로 [ 복사 하고 SEXP포인터를 R로 반환합니다. [호출 될 때마다 새로운 C 객체가 생성되어 R로 반환됩니다.

우리는 R을 통해 객체의 실제 데이터의 각 요소의 메모리 주소에 액세스 할 수 없습니다.하지만 조금만 연주하면 C api를 사용하여 각 주소를 추적 할 수 있습니다.

주소를 얻는 함수 :

ff = inline::cfunction(sig = c(x = "integer"), body = '
             Rprintf("SEXP @ %p\\n", x);

             Rprintf("first element of SEXP actual data @ %p\\n", INTEGER(x));

             for(int i = 0; i < LENGTH(x); i++) 
                 Rprintf("<%d> @ %p\\n", INTEGER(x)[i], INTEGER(x) + i);

             return(R_NilValue);
     ')

그리고 우리의 데이터에 적용 :

x = c(1500L, 2400L, 8800L)  #converted to "integer" for convenience
y = x

lobstr::obj_addr(x)
#[1] "0x1d1c0598"
lobstr::obj_addr(y)
#[1] "0x1d1c0598"

ff(x)
#SEXP @ 0x1d1c0598
#first element of SEXP actual data @ 0x1d1c05c8
#<1500> @ 0x1d1c05c8
#<2400> @ 0x1d1c05cc
#<8800> @ 0x1d1c05d0
#NULL
ff(y)
#SEXP @ 0x1d1c0598
#first element of SEXP actual data @ 0x1d1c05c8
#<1500> @ 0x1d1c05c8
#<2400> @ 0x1d1c05cc
#<8800> @ 0x1d1c05d0
#NULL

객체의 데이터 요소 간의 연속적인 메모리 차이는 int 유형 .

diff(c(strtoi("0x1d1c05c8", 16), 
       strtoi("0x1d1c05cc", 16), 
       strtoi("0x1d1c05d0", 16)))
#[1] 4 4

사용하여 [기능 :

ff(x[1])
#SEXP @ 0x22998358
#first element of SEXP actual data @ 0x22998388
#<1500> @ 0x22998388
#NULL
ff(x[1])
#SEXP @ 0x22998438
#first element of SEXP actual data @ 0x22998468
#<1500> @ 0x22998468
#NULL

이것은 필요 이상의 광범위한 답변 일 수 있으며 실제 기술에 대해서는 단순하지만보다 명확한 "큰"그림을 제공하기를 바랍니다.


대박! R을 완전히 초보자 인 저와 같은 사람들에게 상세하고 명확한 설명을 해주셔서 진심으로 감사드립니다. 또한 R의 유연성과 다른 프로그래밍 언어와의 강력한 상호 작용을 보여주는면에서 매우 인상적입니다. 시간과 도움에 감사드립니다.
— user17911

3

이것은 그것을 보는 한 가지 방법입니다. 더 기술적 인 견해가 있다고 확신합니다. R에서 거의 모든 것이 함수라는 것을 기억하십시오. 여기에는 추출 기능이 포함됩니다 [. 다음과 동등한 내용이 있습니다 x[1].

> `[`(x, 1)
[1] 1500

그래서 당신이하고있는 일은 값을 반환하는 함수를 실행하는 것입니다 (check out ?Extract). 그 값은 정수입니다. 당신이 실행하면 obj_addr(x[1]),이 기능을 평가하고 x[1]다음 당신에게주고 obj_addr()당신이 모두 결합하는 배열의 첫 번째 요소의 기능 복귀가 아니라 주소 x와 y.


내 문제에 대한 귀하의 도움과 관심에 감사드립니다. 실제로 이것은 내가 알지 못한 것입니다. 즉 "추출"로 값을 검색하면 실제로 새로운 객체가 만들어집니다. 내가 말했듯이 나는 정말로 R의 초보자입니다! 시간과 설명 감사합니다.
— user17911
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.