gpt4 book ai didi

c - perlembed/perlcall 示例无限内存增长 - valgrind 说不可能泄漏

转载 作者:太空宇宙 更新时间:2023-11-04 01:36:42 24 4
gpt4 key购买 nike

全部。一段时间以来,我一直在努力反对这个问题……我正在尝试整理一个基本上是 perlembed + perlcall 的示例,并或多或少地从 evpsgi “借用”它。问题是每 1000 次迭代,它的大小会增长大约 1MB。在长期运行的进程中运行时,这不是最好的情况(这是我正在处理的用例)。

如标题所述,如果我使用 valgrind 运行,它会报告没有泄漏可能。我使用 --trace-malloc=yes 运行,看起来 free 只在一大批调用的最后被调用。我知道这可能是 perl 的 MO,但如果它至少重新使用内存并且在操作系统终止进程之前不会增长,那就太好了。

sv_2mortal 的条目提到了有关缓冲区可被“窃取”的内容,但我在代码中添加了对 sv_2mortal 的调用,但没有任何变化。

废话不多说,上代码。请原谅它的 cargo 文化。提前致谢!

/*
*
* cc `perl -MExtUtils::Embed -e ccopts -e ldopts` -Wall -ggdb test_perl_2.c -o test_perl_2
*
* # test.psgi
* use strict;
* use warnings;
* my $app = sub {
* return [ 200, [ test => 1 ], [ sprintf( "%d: Hello!!! from %s\n", $$, __FILE__ ) ] ];
* };
*
*/

#include <stdio.h>
#include <EXTERN.h> /* from the Perl distribution */
#include <perl.h> /* from the Perl distribution */

static PerlInterpreter *perlinterp; /*** The Perl interpreter ***/
static SV *app;

void do_stuff( void );
SV * get_stuff( void );
SV * call_stuff( SV * );

EXTERN_C void xs_init( pTHX );
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
EXTERN_C void xs_init( pTHX ) {
char *file = __FILE__;
dXSUB_SYS;
/* DynaLoader is a special case */
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
}

int main( int argc, char **argv, char **env ) {
char code[ 1024 ];
char psgi[] = "test.psgi";
char *embedding[] = { "", "-e", "0" };

PERL_SYS_INIT3( &argc, &argv, &env );
perlinterp = perl_alloc();
PERL_SET_CONTEXT( perlinterp );
perl_construct( perlinterp );
perl_parse( perlinterp, xs_init, 3, embedding, (char **)NULL );
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;

sprintf( code, "do '%s' or die $@", psgi );
app = eval_pv( code, TRUE ); /* croak_on_error */

do_stuff();

PL_perl_destruct_level = 1;
perl_destruct( perlinterp );
perl_free( perlinterp );
PERL_SYS_TERM();
return 0;
}

void do_stuff( void ) {
int body_lastindex, i, count;
AV *response_av, *body_av;
SV *stuff_sv, *response_sv, *status, *tmp_body_sv, *body_sv;

// count = 10000;
count = 10;
while( count-- ) {

ENTER;
SAVETMPS;

stuff_sv = get_stuff();
response_sv = call_stuff( stuff_sv );

if(
NULL == response_sv ||
! SvROK( response_sv ) ||
SvTYPE( SvRV( response_sv ) ) != SVt_PVAV
) {
printf( "NULL == response_sv\n" );
goto CLIENT_END;
}

response_av = (AV *)SvRV( response_sv );

status = *av_fetch( response_av, 0, 0 );
printf( "status = %ld\n", (long)SvIV( status ) );

body_av = (AV *)SvRV( *av_fetch( response_av, 2, 0 ) );

body_sv = newSV( 0 );

body_lastindex = av_len( body_av );
for( i = 0; i <= body_lastindex; i++ ) {
tmp_body_sv = (SV *)*av_fetch( body_av, i, 0 );
if( SvOK( tmp_body_sv ) ) {
sv_catsv( body_sv, tmp_body_sv );
}
}
printf( "body_sv = %s\n", SvPV_nolen( body_sv ) );

CLIENT_END:
FREETMPS;
LEAVE;
}
}

SV * get_stuff( void ) {
HV *stuff_hv;
// stuff_hv = (HV *)sv_2mortal((SV *)newHV());
stuff_hv = newHV();

if( NULL == hv_store( stuff_hv, "SCRIPT_NAME", strlen( "SCRIPT_NAME" ), newSVpv( "", 0 ), 0 ) ) {
croak( "hv_store( 'SCRIPT_NAME' )" );
}

if( NULL == hv_store( stuff_hv, "REQUEST_METHOD", strlen( "REQUEST_METHOD" ), newSVpv( "GET", 3 ), 0 ) ) {
croak( "hv_store( 'REQUEST_METHOD' )" );
}

if( NULL == hv_store( stuff_hv, "REQUEST_URI", strlen( "REQUEST_URI" ), newSVpv( "/abc?def", 8 ), 0 ) ) {
croak( "hv_store( 'REQUEST_URI' )" );
}

if( NULL == hv_store( stuff_hv, "PATH_INFO", strlen( "PATH_INFO" ), newSVpv( "/abc", 4 ), 0 ) ) {
croak( "hv_store( 'PATH_INFO' )" );
}

if( NULL == hv_store( stuff_hv, "QUERY_STRING", strlen( "QUERY_STRING" ), newSVpv( "def", 3 ), 0 ) ) {
croak( "hv_store( 'QUERY_STRING' )" );
}

return newRV_inc( (SV *)stuff_hv );
}

SV * call_stuff( SV *stuff_sv ) {
SV *response_sv;
int count;

// printf( "REQUEST_URI = %s\n", SvPV_nolen( *hv_fetch( (HV *)SvRV( stuff_sv ), "REQUEST_URI", strlen( "REQUEST_URI" ), 0 ) ) );

dSP;
ENTER;
SAVETMPS;
PUSHMARK( SP );
XPUSHs( stuff_sv ); // stuff_sv is not mortal.
PUTBACK;
count = call_sv( app, G_EVAL | G_SCALAR | G_KEEPERR );
SPAGAIN;
if( SvTRUE( ERRSV ) ) {
response_sv = NULL;
fprintf( stderr, "FATAL: %s", SvPV_nolen( ERRSV ) );
/* CLEAR_ERRSV() is only available 5.8.9 or later */
if( SvMAGICAL( ERRSV ) ) {
mg_free( ERRSV );
mg_clear( ERRSV );
}
sv_setpvn_mg( ERRSV, "", 0 );
POPs; // causes "warning: value computed is not used"
}
else if( count > 0 ) {
response_sv = POPs; // is this mortal?
SvREFCNT_inc( response_sv );
} else {
response_sv = NULL;
}

PUTBACK;
FREETMPS;
LEAVE;
return response_sv;
}

最佳答案

你没有释放任何东西!您从 Perl 获得了一个标量,您自己创建了两个,但没有一个被释放。

泄漏 1

你有:

HV *stuff_hv;
stuff_hv = newHV();
return newRV_inc( (SV *)stuff_hv );

两个问题:

  • 您正在创建一个 refcnt 为 2 的 HV。

    newRV_inc 更改为 newRV_noinc

  • 您永远不会释放它(或将它从 XS 函数作为凡人返回)。

    在完成后使用 SvREFCNT_dec( stuff_sv ),也许是在调用 call_stuff 之后。

泄漏 2

你有:

body_sv = newSV( 0 );

同样,没有相应的释放该标量。你需要

SvREFCNT_dec( body_sv );

printf 之后。

泄漏 3

你有:

response_sv = POPs; // is this mortal?
SvREFCNT_inc( response_sv );

它是否会死亡并不重要。你需要声明它的所有权以防万一,所以 inc 是合适的。但是您必须稍后在完成后释放它。

 SvREFCNT_dec( response_sv );

关于c - perlembed/perlcall 示例无限内存增长 - valgrind 说不可能泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13169768/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com