2010-08-19 6 views
9

SWIG으로 PHP 확장을 만들었습니다. 모든 것이 잘 작동하지만 체인 메서드 호출시 이상한 가비지 수집 동작을 관찰하고 있습니다. 예를 들어,이 작품 :리소스 가비지 수집 너무 일찍

$results = $response->results(); 
$row = $results->get(0)->iterator()->next(); 
printf('%s %s' . "\n", $row->getString(0), $row->getString(1)); 

그러나이 독방 감금 오류를 :

$row = $response->results()->get(0)->iterator()->next(); 
printf('%s %s' . "\n", $row->getString(0), $row->getString(1)); 

유일한 차이점은 첫 번째 동안 두 번째 체인 호출 함께 $results를 생성한다는 것이다.

SWIG는 실제로 PHP에 함수를 공개하고 PHP 프록시 클래스를 생성하여 상호 작용합니다. 이러한 프록시 클래스는 기본적으로 노출 된 각 함수에 전달되는 리소스를 보유하며 그 함수가 일반적으로 사용하는 다른 모든 인수와 함께 사용됩니다. 어쩌면 이러한 프록시 클래스가 문제가되었다고 생각하면서 코드를 무시하고 직접 노출 된 함수를 직접 사용하는 코드를 수정했습니다. 이전과 마찬가지로,이 작품 : 다시

$results = InvocationResponse_results($response->_cPtr); 
$row = TableIterator_next(Table_iterator(Tables_get($results, 0))); 
printf('%s %s' . "\n", Row_getString($row, 0), Row_getString($row, 1)); 

그리고,이 SEG 오류 :

$row = TableIterator_next(Table_iterator(Tables_get(InvocationResponse_results($response->_cPtr), 0))); 
printf('%s %s' . "\n", Row_getString($row, 0), Row_getString($row, 1)); 

을 다시, 유일한 차이점은 첫 번째 체인 동안 통화 함께 $results를 생성한다는 것이다.

이 시점에서 나는 gdb/valgrind에서 잠시 디버깅을했으며 InvocationResponse_results이 반환하는 소멸자가 호출을 함께 연결할 때 너무 일찍 호출됨을 확인했습니다. 관찰하기 위해 노출 된 C++ 함수와 소멸자의 맨 위에 std::cout 문을 삽입했습니다. 이 체인없이 출력 :

InvocationResponse_results() 
Tables_get() 
Table_iterator() 
TableIterator_next() 
__wrap_delete_TableIterator 
Row_getString() 
Row_getString() 
Hola Mundo 
--- 
__wrap_delete_InvocationResponse 
__wrap_delete_Row 
__wrap_delete_Tables 

내가 스크립트의 실행 중에 발생하는 것과 이후에 무슨 구별 할 수 있도록 스크립트의 끝에서 --- 인쇄. Hola Mundoprintf입니다. 나머지는 C++에서 왔습니다. 보시다시피 모든 것이 예상 된 순서대로 호출됩니다. 소멸자는 스크립트가 실행 된 후에 만 ​​호출되지만, TableIterator 소멸자는 예상보다 일찍 호출됩니다. 그러나 이것은 아무런 문제를 일으키지 않았으며 관련이 없습니다. 이제 체인과 출력이 비교 :

InvocationResponse_results의 반환 값이 $results에 저장되지 않고
InvocationResponse_results() 
Tables_get() 
__wrap_delete_Tables 
Table_iterator() 
TableIterator_next() 
__wrap_delete_TableIterator 
Row_getString() 
Segmentation fault (core dumped) 

, 그것은 행복하게 실행도 얻을 수 호출 체인 중이 (Tables_getTable_iterator 사이) 빨리 이전에 수집 쓰레기 결국 문제가 발생하여 궁극적으로 SEG 오류가 발생합니다.

나는 또한 다양한 장소에서 xdebug_debug_zval()을 사용하여 참조 횟수를 검사했지만 이상한 점은 발견하지 못했습니다.

row: (refcount=1, is_ref=0)=resource(21) of type (_p_voltdb__Row) 

내가 지금 이것에 며칠을 보냈어요 난 그냥 아이디어를 밖으로 대해 해요 : 체인과

results: (refcount=1, is_ref=0)=resource(18) of type (_p_std__vectorT_voltdb__Table_t) 
row: (refcount=1, is_ref=0)=resource(21) of type (_p_voltdb__Row) 

을 그리고 $row에 : 여기 $results$row에 출력은 체인없이 , 그래서 이것을 해결하는 방법에 대한 어떤 통찰력이라면 크게 감사 할 것입니다.

+0

초능력 디버깅 능력이없는 사람이라면 누구나 이것을 알아낼 수있을 것 같지 않습니다. '_zend_list_delete'에 중단 점을 넣고 호출 코드가 자원을 삭제하는 이유를 알아내는 것이 좋습니다. 리소스 조회수가 0이거나 직접 삭제 일 수 있습니다. – Artefacto

+0

@Artefacto'__wrap_delete_Tables'가 호출되는 동안'_zend_list_delete' 내부를 들여다 보았고 두 경우 모두 (seg fault와 seg fault가 없음) refcount ('--le-> refcount')가 -1이기 때문에 가비지 수집됩니다. –

+0

그래서'__wrap_delete_Tables'가 한 번에 특정 시간에 호출되었지만 다른 시간에는 호출되지 않고 계속 올라가는 것을 확인하십시오. – Artefacto

답변

1

This은 유사한 디버그 문제 segfaulting에서 문제의 일부로 밝혀졌습니다. (Artefacto가 말한 것)