2012-04-21 35 views
0

我知道shift,push和pop是用於添加/刪除數組元素的Array方法,但我不確定內存中實際發生了什麼。舉例來說,刪除數組的最後一個元素的方法pop。它讓我想起堆棧中使用的LIFO命令,但是我認爲這個元素並沒有像彙編編程那樣真正「彈出」而是整個數組的索引被移位。我真的不知道,如果有人能幫助我,我會很感激。Ruby:內存中的Shift,Push和Pop

回答

5

Ruby適用於那些患有這種想法的程序員。我們相信那些執行這些程序的人可以在優化性能和內存管理方面做得最好。

如果你只是好奇,這裏是在Rubinius的陣列#移位代碼:

def shift(n=undefined) 
    Rubinius.check_frozen 

    if n.equal? undefined 
     return nil if @total == 0 
     obj = @tuple.at @start 
     @tuple.put @start, nil 
     @start += 1 
     @total -= 1 

     obj 
    else 
     n = Rubinius::Type.coerce_to(n, Fixnum, :to_int) 
     raise ArgumentError, "negative array size" if n < 0 

     slice!(0, n) 
    end 
end 

而且你可以看到,一個陣列本身就是一個Rubinius的元組::,並在元組的定義,它是Rubinius :: Array。它所做的只是將開始位置放到下一個位置。我不確定他們會釋放它使用的空間(我認爲它會這樣),因爲你必須深入挖掘。

在官方1.9.3中,我不知道它是如何實現的,因爲它們在C中執行,而且它們很難閱讀。如果你想知道更多的細節,你可以在GitHub上發佈Rubinius,或者從ruby-lang.org上下載官方的1.9.3,並閱讀源代碼。您可以瞭解更多關於C/C++編程太:)


於是我趕緊通過官方1.9.3的代碼去了,這是數組#轉換功能定義:

static VALUE 
rb_ary_shift_m(int argc, VALUE *argv, VALUE ary) 
{ 
    VALUE result; 
    long n; 

    if (argc == 0) { 
    return rb_ary_shift(ary); 
    } 

    rb_ary_modify_check(ary); 
    result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST); 
    n = RARRAY_LEN(result); 
    if (ARY_SHARED_P(ary)) { 
    if (ARY_SHARED_NUM(ARY_SHARED(ary)) == 1) { 
     rb_mem_clear(RARRAY_PTR(ary), n); 
    } 
     ARY_INCREASE_PTR(ary, n); 
    } 
    else { 
    MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+n, VALUE, RARRAY_LEN(ary)-n); 
    } 
    ARY_INCREASE_LEN(ary, -n); 

    return result; 
} 

這line:

MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+n, VALUE, RARRAY_LEN(ary)-n); 

它告訴我們它實際上移動的內存塊偏移n。這可能就是爲什麼這位官員比魯比尼烏斯慢的原因......魯比尼烏斯在大型記憶中佔據優勢,但是可以節省時間;官方消耗更少的內存,但需要更多的時間...

+0

虐待檢查c源代碼。我很好奇。 – 2012-04-21 03:42:07

+0

@BhubhuHbuhdbus稍微更新:)我也經歷了C代碼。 – texasbruce 2012-04-21 03:59:41