shared_ptr 통과 비용
내 응용 프로그램 전체에서 std :: tr1 :: shared_ptr을 광범위하게 사용합니다. 여기에는 함수 인수로 객체 전달이 포함됩니다. 다음을 고려하세요:
class Dataset {...}
void f( shared_ptr< Dataset const > pds ) {...}
void g( shared_ptr< Dataset const > pds ) {...}
...
shared_ptr을 통해 데이터 세트 객체를 전달하면 f 및 g 내부에 존재하는 것이 보장되지만 함수는 수백만 번 호출 될 수 있으며 이로 인해 많은 shared_ptr 객체가 생성되고 파괴됩니다. 다음은 최근 실행 된 평면 gprof 프로필의 일부입니다.
각 샘플은 0.01 초로 계산됩니다. 누적 자체 합계 % 시간 초 초 호출 s / call s / call name 9.74 295.39 35.12 2451177304 0.00 0.00 std :: tr1 :: __ shared_count :: __ shared_count (std :: tr1 :: __ shared_count const &) 8.03 324.34 28.95 2451252116 0.00 0.00 std :: tr1 :: __ shared_count :: ~ __shared_count ()
따라서 런타임의 ~ 17 %가 shared_ptr 객체를 사용한 참조 계산에 사용되었습니다. 이것은 정상입니까?
내 응용 프로그램의 많은 부분이 단일 스레드이며 일부 기능을 다음과 같이 다시 작성하려고 생각했습니다.
void f( const Dataset& ds ) {...}
및 통화 교체
shared_ptr< Dataset > pds( new Dataset(...) );
f( pds );
와
f( *pds );
프로그램의 흐름이 f () 내부에있는 동안 객체가 파괴되지 않을 것이라고 확신하는 곳에서. 하지만 함수 시그니처 / 호출을 변경하기 전에 shared_ptr 전달의 일반적인 성능 저하가 무엇인지 알고 싶었습니다. 매우 자주 호출되는 함수에는 shared_ptr을 사용하면 안됩니다.
모든 입력을 주시면 감사하겠습니다. 읽어 주셔서 감사합니다.
-아르 템
업데이트 : 수락 할 몇 가지 기능을 변경 한 후 const Dataset&
새 프로필은 다음과 같습니다.
각 샘플은 0.01 초로 계산됩니다. 누적 자체 합계 % 시간 초 초 호출 s / call s / call name 0.15 241.62 0.37 24981902 0.00 0.00 std :: tr1 :: __ shared_count :: ~ __shared_count () 0.12 241.91 0.30 28342376 0.00 0.00 std :: tr1 :: __ shared_count :: __ shared_count (std :: tr1 :: __ shared_count const &)
소멸자 호출 수가 복사 생성자 호출 수보다 적다는 점에 약간 의아해하지만 전반적으로 연관된 런타임 감소에 매우 만족합니다. 그들의 조언에 감사드립니다.
항상 당신을 통과 shared_ptr
하여 const를 참조 :
void f(const shared_ptr<Dataset const>& pds) {...}
void g(const shared_ptr<Dataset const>& pds) {...}
편집 : 다른 사람이 언급 한 안전 문제에 관하여 :
shared_ptr
응용 프로그램 전체에서 많이 사용 하는 경우 값을 전달하는 데 엄청난 시간이 걸립니다 (50 % 이상 진행되는 것을 보았습니다).- 인수가 널이 아닐 때
const T&
대신 사용하십시오const shared_ptr<T const>&
. - 성능이 문제 일
const shared_ptr<T const>&
때보 다 사용하는 것이 더 안전const T*
합니다.
shared_ptr은 나중에 사용할 수 있도록 유지하는 함수 / 객체에 전달하기 위해서만 필요합니다. 예를 들어, 일부 클래스는 작업자 스레드에서 사용하기 위해 shared_ptr을 유지할 수 있습니다. 단순한 동기 호출의 경우 일반 포인터 또는 참조를 사용하는 것으로 충분합니다. shared_ptr은 일반 포인터를 사용하여 완전히 대체해서는 안됩니다.
make_shared를 사용하지 않는 경우 사용할 수 있습니까? 동일한 메모리 영역에서 참조 횟수와 개체를 찾으면 캐시 일관성과 관련된 성능 향상을 확인할 수 있습니다. 어쨌든 시도할만한 가치가 있습니다.
성능이 중요한 응용 프로그램에서는 모든 개체 생성 및 삭제, 특히 중복 개체 생성 및 삭제를 피해야합니다.
shared_ptr이 무엇을하는지 고려하십시오. 새로운 객체를 생성하고 채울뿐만 아니라 공유 상태를 참조하여 참조 정보를 증가시키고 객체 자체는 아마도 캐시에서 악몽이 될 완전히 다른 곳에있을 것입니다.
아마도 여러분은 shared_ptr이 필요합니다 (로컬 객체로 도망 갈 수 있다면 힙에서 하나를 할당하지 않을 것이기 때문입니다), 심지어 shared_ptr 역 참조의 결과를 "캐시"할 수도 있습니다 :
void fn(shared_ptr< Dataset > pds)
{
Dataset& ds = *pds;
for (i = 0; i < 1000; ++i)
{
f(ds);
g(ds);
}
}
... 왜냐하면 * pds조차도 절대적으로 필요한 것보다 더 많은 메모리를 필요로하기 때문입니다.
It sounds like you really know what you're doing. You've profiled your application, and you know exactly where cycles are being used. You understand that calling the constructor to a reference counting pointer is expensive only if you do it constantly.
The only heads up I can give you is: suppose inside function f(t *ptr), if you call another function that uses shared pointers, and you do other(ptr) and other makes a shared pointer of the raw pointer. When that second shared pointers' reference count hits 0 then you have effectively deleted your object....even though you didn't want to. you said you used reference counting pointers a lot, so you have to watch out for corner cases like that.
EDIT: You can make the destructor private, and only a friend of the shared pointer class, so that way the destructor can only be called by a shared pointer, then you're safe.
Doesn't prevent multiple deletions from shared pointers. As per comment from Mat.
ReferenceURL : https://stackoverflow.com/questions/2502394/the-cost-of-passing-by-shared-ptr
'developer tip' 카테고리의 다른 글
Apache 대신 Glassfish를 사용하는 이유는 무엇입니까? (0) | 2020.12.31 |
---|---|
작은 정수 배열 지우기 : memset 대 for 루프 (0) | 2020.12.31 |
Android의 VideoView에서 비디오 재생 (0) | 2020.12.31 |
Xcode를 업데이트하는 방법은 무엇입니까? (0) | 2020.12.31 |
Android에서 로그인 화면 / 활동을 만드는 올바른 방법은 무엇입니까? (0) | 2020.12.31 |