programing

글로벌 신규 및 삭제를 오버로드하는 이유는 무엇입니까?

projobs 2021. 1. 17. 10:25
반응형

글로벌 신규 및 삭제를 오버로드하는 이유는 무엇입니까?


OS 또는 임베디드 시스템의 일부를 프로그래밍하지 않는 한 그렇게 할 이유가 있습니까? 자주 생성되고 파괴되는 일부 특정 클래스의 경우 메모리 관리 기능을 오버로드하거나 개체 풀을 도입하면 오버 헤드가 낮아질 수 있지만 이러한 작업을 전역 적으로 수행 할 수 있습니까?

또한
오버로드 된 삭제 기능에서 버그를 발견했습니다. 메모리가 항상 해제되지는 않았습니다. 그리고 그것은 메모리가 중요하지 않은 애플리케이션에있었습니다. 또한 이러한 과부하를 비활성화하면 성능이 0.5 % 만 저하됩니다.


우리는 여러 가지 이유로 내가 일하는 전역 new 및 delete 연산자를 오버로드합니다.

  • 모든 소규모 할당 풀링 -오버 헤드 감소, 조각화 감소, 소규모 할당량이 많은 앱의 성능 향상
  • 알려진 수명을 가진 프레임 할당-이 기간이 끝날 때까지 모든 해제를 무시한 다음 모두 함께 해제합니다 (확실히 글로벌보다 로컬 연산자 오버로드를 사용하여 더 많이 수행합니다).
  • 정렬 조정-캐시 라인 경계 등
  • alloc fill- 초기화되지 않은 변수의 사용을 노출하는 데 도움
  • 무료 채우기 -이전에 삭제 된 메모리 사용량을 노출하는 데 도움
  • 지연된 자유 -자유 채우기의 효과를 높이고 때때로 성능을 향상시킵니다.
  • 센티넬 또는 펜스 포스트 -버퍼 오버런, 언더런 및 가끔 발생하는 와일드 포인터를 노출하는 데 도움이됩니다.
  • 할당 재 지정 -NUMA, 특수 메모리 영역을 설명하거나 메모리에서 별도의 시스템을 유지하기 위해 (예 : 임베디드 스크립팅 언어 또는 DSL)
  • 가비지 수집 또는 정리-포함 된 스크립팅 언어에 다시 유용합니다.
  • 힙 확인 -N 개의 할당 / 해제 할 때마다 힙 데이터 구조를 살펴보고 모든 것이 정상인지 확인할 수 있습니다.
  • 누수 추적사용량 스냅 샷 / 통계 (스택, 할당 기간 등)를 포함한 회계

새 / 삭제 계정의 개념은 매우 유연하고 강력합니다. 예를 들어 할당이 발생할 때마다 활성 스레드에 대한 전체 호출 스택을 기록하고 이에 대한 통계를 집계 할 수 있습니다. 어떤 이유로 든 로컬에 보관할 공간이없는 경우 네트워크를 통해 스택 정보를 전송할 수 있습니다. 여기에서 수집 할 수있는 정보 유형은 상상력 (물론 성능)에 의해서만 제한됩니다.

동일한 오버로드에서 수집 한 통계를 기반으로 전체 앱에 걸쳐 많은 공통 디버깅 기능을 매달고 전체적으로 개선하는 것이 편리하기 때문에 글로벌 오버로드를 사용합니다.

우리는 여전히 개별 유형에 대해 사용자 지정 할당자를 사용합니다. 많은 경우에 STL 데이터 구조의 단일 사용 지점에 대한 사용자 지정 할당자를 제공하여 얻을 수있는 속도 향상 또는 기능은 글로벌 오버로드에서 얻을 수있는 일반적인 속도 향상을 훨씬 능가합니다.

C / C ++ 용 할당 자 및 디버깅 시스템 중 일부를 살펴보면 다음과 같은 아이디어를 빠르게 얻을 수 있습니다.

(오래되었지만 중요한 책 중 하나는 Writing Solid Code 이며, C로 사용자 지정 할당자를 제공하려는 많은 이유를 설명하며 대부분은 여전히 ​​매우 관련이 있습니다.)

분명히 이러한 훌륭한 도구를 사용할 수 있다면 직접 롤링하는 것보다 사용하고 싶을 것입니다.

더 빠르고, 쉬우 며, 비즈니스 / 법적 번거 로움이 적거나, 아직 플랫폼에서 사용할 수있는 것이 없거나, 더 유익한 상황이 있습니다. 글로벌 오버로드를 파헤쳐 작성하세요.


new를 오버로드하고 삭제하는 가장 일반적인 이유는 단순히 메모리 누수 및 메모리 사용 통계를 확인하는 것입니다. "메모리 누수"는 일반적으로 메모리 오류로 일반화됩니다. 이중 삭제 및 버퍼 오버런과 같은 것을 확인할 수 있습니다.

그 이후의 용도는 일반적으로 가비지 수집풀링같은 메모리 할당 체계 입니다.

다른 모든 경우는 다른 답변 (디스크에 로깅, 커널 사용)에서 언급 한 특정 사항입니다.


메모리 태깅과 같이 여기에 언급 된 다른 중요한 용도 외에도 앱의 모든 할당이 성능 및 조각화에 막대한 영향을 미치는 고정 블록 할당을 거치도록하는 유일한 방법이기도합니다.

예를 들어, 고정 된 블록 크기를 가진 일련의 메모리 풀이있을 수 있습니다. 전역을 재정의 new하면 모든 61 바이트 할당을 예를 들어 64 바이트 블록이있는 풀로, 모든 768-1024 바이트 할당을 1024b 블록 풀에, 그 이상의 모든 할당을 2048 바이트 블록 풀에 할당 할 수 있습니다. 일반 비정형 힙에 8kb 이상입니다.

고정 블록 할당자는 힙에서 엉뚱한 방식으로 할당하는 것보다 훨씬 빠르고 단편화 가능성이 적기 때문에 엉뚱한 3d 파티 코드도 주소 공간 전체에 똥을 내지 않고 풀에서 할당하도록 강제 할 수 있습니다.

이것은 게임과 같이 시간과 공간이 중요한 시스템에서 자주 수행됩니다. 280Z28, Meeh 및 Dan Olson이 그 이유를 설명했습니다.


UnrealEngine3는 핵심 메모리 관리 시스템의 일부로 전역 신규 및 삭제를 오버로드합니다. 다양한 기능 (프로파일 링, 성능 등)을 제공하는 여러 할당자가 있으며이를 통과하려면 모든 할당이 필요합니다.

편집 : 내 자신의 코드에 대해서는 최후의 수단으로 만 할 것입니다. 그리고 그것은 거의 절대적으로 그것을 사용하지 않을 것임을 의미합니다. 그러나 내 개인 프로젝트는 분명히 훨씬 작거나 매우 다른 요구 사항입니다.


일부 실시간 시스템은 초기화 후 사용되는 것을 방지하기 위해 오버로드합니다.


new & delete를 오버로딩하면 메모리 할당에 태그를 추가 할 수 있습니다. 시스템 또는 제어 또는 미들웨어별로 할당에 태그를 지정합니다. 런타임에 각각의 사용량을 볼 수 있습니다. UI와 분리 된 파서의 사용법이나 미들웨어가 실제로 얼마나 많이 사용하고 있는지보고 싶을 수도 있습니다!

또한 할당 된 메모리 주변에 보호 대역을 배치하는 데 사용할 수도 있습니다. 앱이 충돌하는 경우 주소를 살펴볼 수 있습니다. 내용이 "0xABCDABCD"(또는 가드로 선택한 항목)로 표시되면 소유하지 않은 메모리에 액세스하는 것입니다.

아마도 delete를 호출 한 후에 유사하게 인식 할 수있는 패턴으로이 공간을 채울 수 있습니다. VisualStudio가 디버그에서 비슷한 일을한다고 생각합니다. 0xCDCDCDCD로 초기화되지 않은 메모리를 채우지 않습니까?

마지막으로 조각화 문제가있는 경우이를 사용하여 블록 할당 자로 리디렉션 할 수 있습니까? 이것이 얼마나 자주 문제가되는지 잘 모르겠습니다.


new 및 delete에 대한 호출이 환경에서 작동하지 않는 경우이를 오버로드해야합니다.

예를 들어 커널 프로그래밍에서 기본 new 및 delete는 메모리를 할당하기 위해 사용자 모드 라이브러리에 의존하므로 작동하지 않습니다.


실용적인 관점에서, operator new가 어쨌든 그것을 호출 할 것이기 때문에 시스템 라이브러리 수준에서 malloc을 재정의하는 것이 더 나을 수 있습니다.

Linux에서는 다음 예제와 같이 시스템 1 대신 malloc의 고유 버전을 배치 할 수 있습니다.

http://developers.sun.com/solaris/articles/lib_interposers.html

이 기사에서는 성능 통계를 수집하려고합니다. 그러나 free를 재정의하면 메모리 누수를 감지 할 수도 있습니다.

Since you are doing this in a shared library with LD_PRELOAD, you don't even need to recompile your application.


I've seen it done in a system that for 'security'* reasons was required to write over all memory it used on de-allocation. The approach was to allocate an extra few bytes at the start of each block of memory which would contain the size of the overall block which would then be overwritten with zeros on delete.

This had a number of problems as you can probably imagine but it did work (mostly) and saved the team from reviewing every single memory allocation in a reasonably large, existing application.

Certainly not saying that it is a good use but it is probably one of the more imaginative ones out there...

* sadly it wasn't so much about actual security as the appearance of security...


Photoshop plugins written in C++ should override operator new so that they obtain memory via Photoshop.


I've done it with memory mapped files so that data written to the memory is automatically also saved to disk.
It's also used to return memory at a specific physical address if you have memory mapped IO devices, or sometimes if you need to allocate a certain block of contiguous memory.

But 99% of the time it's done as a debugging feature to log how often, where, when memory is being allocated and released.


It's actually pretty common for games to allocate one huge chunk of memory from the system and then provide custom allocators via overloaded new and delete. One big reason is that consoles have a fixed memory size, making both leaks and fragmentation large problems.

Usually (at least on a closed platform) the default heap operations come with a lack of control and a lack of introspection. For many applications this doesn't matter, but for games to run stably in fixed-memory situations the added control and introspection are both extremely important.


It can be a nice trick for your application to be able to respond to low memory conditions by something else than a random crash. To do this your new can be a simple proxy to the default new that catches its failures, frees up some stuff and tries again.

The simplest technique is to reserve a blank block of memory at start-up time for that very purpose. You may also have some cache you can tap into - the idea is the same.

When the first allocation failure kicks in, you still have time to warn your user about the low memory conditions ("I'll be able to survive a little longer, but you may want to save your work and close some other applications"), save your state to disk, switch to survival mode, or whatever else makes sense in your context.


The most common use case is probably leak checking.

Another use case is when you have specific requirements for memory allocation in your environment which are not satisfied by the standard library you are using, like, for instance, you need to guarantee that memory allocation is lock free in a multi threaded environment.


As many have already stated this is usually done in performance critical applications, or to be able to control memory alignment or track your memory. Games frequently use custom memory managers, especially when targeting specific platforms/consoles.

Here is a pretty good blog post about one way of doing this and some reasoning.


Overloaded new operator also enables programmers to squeeze some extra performance out of their programs. For example, In a class, to speed up the allocation of new nodes, a list of deleted nodes is maintained so that their memory can be reused when new nodes are allocated.In this case, the overloaded delete operator will add nodes to the list of deleted nodes and the overloaded new operator will allocate memory from this list rather than from the heap to speedup memory allocation. Memory from the heap can be used when the list of deleted nodes is empty.

ReferenceURL : https://stackoverflow.com/questions/1152511/any-reason-to-overload-global-new-and-delete

반응형