2016-11-04 6 views
1

私はC++ apisをperlで公開していた私の会社の本当に古いコードベースを扱わなければなりませんでした。Perl XSガベージコレクション

コードレビューでは、C++で割り当てられていたメモリをガベージコレクトする必要があると提案しました。ここで

は、コードのスケルトンです:

char* convert_to_utf8(char *src, int length) { 
    . 
    . 
    . 
    length = get_utf8_length(src); 
    char *dest = new char[length]; 
    . 
    . 
    // No delete 
    return dest; 
} 

のPerl XS定義:

PROTOTYPE: ENABLE 

char * _xs_convert_to_utf8(src, length) 
    char *src 
    int length 

CODE: 
    RETVAL = convert_to_utf8(src, length) 

OUTPUT: 
    RETVAL 

ので、私はC++関数で作成されたメモリはガベージのPerlによって収集されないだろうというコメントがありました。そして、2つのJava開発者は、perlがC++によって割り当てられたメモリをガベージコレクトするので、クラッシュすると思っています。私は以下のコードを提案した。

CLEANUP: 
    delete[] RETVAL 

私は間違っていますか?

また、このコードを実行し、CLEANUPセクションの有無にかかわらず、メモリ使用率の向上を示しました。しかし、彼らはそれを証明する正確な文書を求めていて、見つけられませんでした。

たPerlクライアント:

use ExtUtils::testlib; 
use test; 

for (my $i=0; $i<100000000;$i++) { 
    my $a = test::hello(); 
} 

C++コード:

#define PERL_NO_GET_CONTEXT 
#include "EXTERN.h" 
#include "perl.h" 
#include "XSUB.h" 

#include "ppport.h" 
#include <stdio.h> 

char* create_mem() { 
    char *foo = (char*)malloc(sizeof(char)*150); 
    return foo; 
} 

XSコード:

MODULE = test  PACKAGE = test  
    char * hello() 
CODE: 
    RETVAL = create_mem(); 
OUTPUT: 
    RETVAL 
CLEANUP: 
    free(RETVAL); 
+0

なぜ彼らはPerlがC++によって割り当てられたメモリをガベージコレクトしようと思うのでしょうか?あなたが証明することを求められているのは正確に何ですか? – ysth

+0

@ysth PerlはC++によって割り当てられたメモリをガベージコレクションしません – var

答えて

3

私は怖いことを書いた(と書き込み)人のPerl XSおそらく、Perlは他の言語(C++など)でメモリ割り当てを魔法のように検出してt帽子perlgutsのマニュアルページには、Perl XS API経由で使用されるすべてのメモリが、それを行うためにPerlのマクロを使用しなければならないということが記載されています。

+0

Re * Perl XS API経由で使用されるすべてのメモリはPerlのマクロを使用しなければなりません*、OPの 'mem'はそのようなメモリではありません。その文章は、Perlが割り当てを解除する必要があるメモリを参照しています。 (例えば、 'SvPV_set'に渡されたバッファはPerlのアロケータを使って調整する必要がありますが、' SvPV_set'はあなたが通常使っているものではありません)OPの 'mem'はアロケータによって安全に割り当てられます。 (対応するデアロケータを使用して常に解放する必要があります)。 – ikegami

1

XSコードを書くときは、C(またはC++コード)コードを記述しています。適切なC/C++を書く必要があります。これには、適切なときに割り当てられたメモリの割り当てを解除することが含まれます。

void hello() { 
    dSP;      // Declare and init SP, the stack pointer used by mXPUSHs. 
    char* mem = create_mem(); 
    mXPUSHs(newSVpv(mem, 0)); // Create a scalar, mortalize it, and push it on the stack. 
    free(mem);     // Free memory allocated by create_mem(). 
    XSRETURN(1); 
} 

newSVpvはむしろそれの所持を取るよりも、memのコピーを作成しますので、上記のは明らかfree(mem)を解放する必要があることを示しています


あなたはXSを作成することを望む糊機能は以下のとおりです。 mem


XSでは、あなたは

void hello() 
CODE: 
    {       // A block is needed since we're declaring vars. 
     char* mem = create_mem(); 
     mXPUSHs(newSVpv(mem, 0)); 
     free(mem); 
     XSRETURN(1); 
    } 

として、あるいはあなたがそのような RETVALCLEANUPなどXSの機能を利用することができることを書くことができます。

また、戻り値をスカラーに変換する方法を定義するtypemapを利用することもできます。

char* hello() 
CODE: 
    RETVAL = create_mem(); 
OUTPUT: 
    RETVAL 
CLEANUP: 
    free(RETVAL); 

これらの3つはすべて完全に許容されます。


死に至るノート。

償却は遅延参照カウントの減少です。 helloによって作成されたSVをデクリメントする場合は、helloが返される前に、helloが返される前に割り当てが解除されます。それを死に至らせることによって、呼び出し側がそれを調べたり所有したりするまで(参照カウントを増やすことによって)、割り振り解除されることはありません。

関連する問題