Yudum oluşturulan uzantısı bellek sızıntısı

0 Cevap php

SWIG kullanarak PHP C + + kütüphanesi sararak bir bellek sızıntısı sorunu yaşıyorum. Bu yönetmenler etkinse karmaşık türleri içeren C + + callbacks PHP gönderilir zaman ne gibi görünüyor. Burada kaçak yeniden bağımsız bir örnek:

Client.hpp:

#ifndef CLIENT_HPP_
#define CLIENT_HPP_

#include <vector>
#include "ProcedureCallback.hpp"

class Client {
public:
    void invoke(ProcedureCallback *callback) {
        callback->callback(std::vector<int>(0));
    }
};

#endif /* CLIENT_HPP_ */

ProcedureCallback.hpp:

#ifndef PROCEDURECALLBACK_HPP_
#define PROCEDURECALLBACK_HPP_

#include <vector>

class ProcedureCallback {
public:
    virtual void callback(std::vector<int>) = 0;
};

#endif /* PROCEDURECALLBACK_HPP_ */

Yani bu kullanmak için oluşturduğunuz bir Client, geçmek bir ProcedureCallback Müşterinin invoke yöntemi sınıflandırma, ve İstemci sonra gider ve çağrılar {[(3)] bunu verdi ve boş bir int vektör geçer ne} yöntemi.

Bu yudum arayüz dosyası:

%module(directors="1") debugasync
%feature("director");

%{
#include "Client.hpp"
#include "ProcedureCallback.hpp"
%}

%include "Client.hpp"
%include "ProcedureCallback.hpp"

Onun çıkışı çok büyük, bu yüzden yerine pastebin koydu: debugasync_wrap.cpp. Bu dosyada ilgi muhtemelen SwigDirector_ProcedureCallback :: callback (line 1319) 'dir:

void SwigDirector_ProcedureCallback::callback(std::vector< int > arg0) {
  zval *args[1];
  zval *result, funcname;
  MAKE_STD_ZVAL(result);
  ZVAL_STRING(&funcname, (char *)"callback", 0);
  if (!swig_self) {
    SWIG_PHP_Error(E_ERROR, "this pointer is NULL");
  }

  zval obj0;
  args[0] = &obj0;
  {
    SWIG_SetPointerZval(&obj0, SWIG_as_voidptr(&arg0), SWIGTYPE_p_std__vectorT_int_t, 2);
  }
  call_user_function(EG(function_table), (zval**)&swig_self, &funcname,
    result, 1, args TSRMLS_CC);
  FREE_ZVAL(result);
  return;
fail:
  zend_error(SWIG_ErrorCode(),"%s",SWIG_ErrorMsg());
}

Bu aynı zamanda ilgi (line 827) olabilir:

static void
SWIG_ZTS_SetPointerZval(zval *z, void *ptr, swig_type_info *type, int newobject TSRMLS_DC) {
  swig_object_wrapper *value=NULL;
  /*
   * First test for Null pointers.  Return those as PHP native NULL
   */
  if (!ptr ) {
    ZVAL_NULL(z);
    return;
  }
  if (type->clientdata) {
    if (! (*(int *)(type->clientdata)))
      zend_error(E_ERROR, "Type: %s failed to register with zend",type->name);
    value=(swig_object_wrapper *)emalloc(sizeof(swig_object_wrapper));
    value->ptr=ptr;
    value->newobject=newobject;
    if (newobject <= 1) {
      /* Just register the pointer as a resource. */
      ZEND_REGISTER_RESOURCE(z, value, *(int *)(type->clientdata));
    } else {
      /*
       * Wrap the resource in an object, the resource will be accessible
       * via the "_cPtr" member. This is currently only used by
       * directorin typemaps.
       */
      value->newobject = 0;
      zval *resource;
      MAKE_STD_ZVAL(resource);
      ZEND_REGISTER_RESOURCE(resource, value, *(int *)(type->clientdata));
      zend_class_entry **ce = NULL;
      zval *classname;
      MAKE_STD_ZVAL(classname);
      /* _p_Foo -> Foo */
      ZVAL_STRING(classname, (char*)type->name+3, 1);
      /* class names are stored in lowercase */
      php_strtolower(Z_STRVAL_PP(&classname), Z_STRLEN_PP(&classname));
      if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &ce TSRMLS_CC) != SUCCESS) {
        /* class does not exist */
        object_init(z);
      } else {
        object_init_ex(z, *ce);
      }
      Z_SET_REFCOUNT_P(z, 1);
      Z_SET_ISREF_P(z);
      zend_hash_update(HASH_OF(z), (char*)"_cPtr", sizeof("_cPtr"), (void*)&resource, sizeof(zval), NULL);
      FREE_ZVAL(classname);
    }
    return;
  }
  zend_error(E_ERROR, "Type: %s not registered with zend",type->name);
}

Ve PHP bellek sızıntısı göstermek için (debugasync.php Ben de pastebin yüklediğim yudum tarafından oluşturulan proxy sınıfları bir dizi):

<?php

require('debugasync.php');

class MyCallback extends ProcedureCallback {
    public function callback($intVector) {}
}

$client = new Client();
$callback = new MyCallback();

while (true) {
    print(number_format(memory_get_usage()) . "\n");
    for ($j = 0; $j < 1000; $j++) {
        $client->invoke($callback);
    }
}

Bu baskılar bellek kullanımı, 1k çağırmaları ve tekrarlar yapar. Çalışan bir hızla büyüyen bir bellek alanı gösterir:

$ php test.php 
692,664
1,605,488
2,583,232
3,634,776
4,538,784
5,737,760
6,641,768
7,545,816
^C

Ayrıca not olduğunu C + + geri geçerse bir ilkel (yani int) yerine kompleks tipi (yani std::vector<int>), bellek sızıntısı değildir.

Bu bellek sızıntısı nedeni nedir?

Ve daha genel olarak, ben bu çözmek için hangi araçları kullanabilir? Valgrind en masif gerçekten bile hata ayıklama sembolleri ile PHP'yi sonra, neler oluyor daraltmak mümkün olmamıştır.

0 Cevap