C ++에서 메모리 관리에 소요되는 프로그래머 시간


39

가비지 수집 언어에 익숙한 사람들은 종종 C ++의 메모리 관리가 무섭습니다. 같은 도구가 있습니다 auto_ptr그리고 shared_ptr당신을위한 메모리 관리 많은 작업을 처리 할 수있는가. 많은 C ++ 라이브러리가 이러한 도구보다 우선하며 메모리 관리 작업을 처리하는 고유 한 방법이 있습니다.

메모리 관리 작업에 얼마나 많은 시간을 소비합니까?

나는 그것이 사용하는 라이브러리 세트에 크게 의존한다고 생각하므로 귀하의 답변에 적용되는 라이브러리와 더 나은지 또는 더 나쁜지를 말하십시오.


1
그다지 중요하지는 않습니다. 특히 C ++ 0x, 참조 및 STL의 경우. 메모리 관리없이 코드를 작성할 수도 있습니다.
Coder

9
일반적으로 : 경험이 많지 않은 한. C ++ (-> 보통 사냥 메모리 / 리소스 누수)에 익숙하지 않은 경우 많이 있습니다.
MaR

1
요즘에는 오래된 참조를 쫓는 것에 대한 실제 질문이 있습니다. 그리고 그것은 매번 꽤 분명합니다, 그것은 전에 잡히지 않았다는 것을 짜증나게합니다 : p
Matthieu M.

나는 이것이 오래되었다는 것을 알고 있지만 IMO 메모리 관리는 훌륭한 프로그래머가되기위한 필수 요소입니다. STL 컨테이너와 같은 추상화는 훌륭하지만 메모리를 모르는 것은 계산 자체에 대한 아이디어와 반대입니다. 프로그래머의 무기고에서 대수 조작, 논리 및 반복을 제거하는 방법을 묻습니다.
imallett

" 메모리 관리 를 디버깅 하는 데 시간이 얼마나 걸립니까?" 본질적으로 메모리 관리는 가능하며 C ++에서는 그렇게 어렵지 않습니다. 사실 : 그것을 설정하는 것은 정확한 기술이며, 성가신 경향이 있습니다. 시간이 지남에 따라 쌓인 불규칙한 행동으로 오래된 오류를 추적하고 눈치 채지 못할 수도 있습니다. 그렇기 때문에 현대의 가비지 수집 언어 (녹 스러울 거라 생각합니다)가 일반적인 오류를 검사하는 데 많은 책임을지게되었습니다.
ZJR

답변:


54

최신 C ++은 메모리 관리에 대해 걱정할 필요가 없습니다. 즉, 최적화 목적으로 또는 직접 컨텍스트를 통해 메모리를 수동으로 구성해야 할 때까지 (큰 제약 하드웨어를 생각하십시오). 나는 원시 메모리를 조작하지 않고 전체 게임을 작성했지만 다른 언어와 마찬가지로 작업에 적합한 도구 인 컨테이너 사용에 대해서만 걱정합니다.

따라서 프로젝트에 따라 다르지만 대부분의 경우 메모리 관리가 아니라 개체 수명 만 처리해야합니다. 이것은 스마트 포인터를 사용하여 해결되는데 , 이는 RAII로 인한 관용적 C ++ 도구 중 하나입니다 .

RAII 를 이해하면 메모리 관리는 문제가되지 않습니다.

그런 다음 원시 메모리에 액세스해야 할 경우 "모든 위치"가 아닌 풀 객체 구현과 같이 매우 구체적이고 지역화되고 식별 가능한 코드로 처리해야합니다.

이러한 종류의 코드 외에는 메모리를 조작 할 필요가 없으며 객체 수명 만 유지됩니다.

"하드"부분은 RAII를 이해하는 것입니다.


10
물론 그렇습니다. 지난 5 년 동안 레거시 코드로 작업 할 때 "삭제"만 작성했습니다.
drxzcl

3
나는 스택 크기가 제한된 임베디드 환경에서 일합니다. RAII만큼 멋지지만 스택 공간이 부족하면 제대로 작동하지 않습니다. 다시 포인터 미세 관리로 돌아 왔습니다.
bastibe

1
@ nikie API를 조작하는 코드에서 라이브러리 스마트 포인터를 사용하고 응용 프로그램 고유의 코드에서 표준 또는 부스트 스마트 포인터를 사용합니다 (내가 결정하는 사람이라면). 애플리케이션에서 사용되는 방식을 추상화하는 일부 모듈에서 라이브러리 코드를 분리 할 수 ​​있으면 종속성으로 인한 API 오염을 피할 수 있습니다.
Klaim 18

12
@Paperflyer : 하나의 복잡한 구현이 없으면 RAII는 delete수동 보다 많은 스택 공간을 차지하지 않습니다 .
DeadMG

2
@Paperflyer : 힙의 스마트 포인터는 같은 공간을 차지합니다. 차이점은 컴파일러가 함수의 모든 종료에 자원 할당 해제 코드를 삽입한다는 것입니다. 그리고 이것이 널리 사용되기 때문에, 이것은 일반적으로 잘 최적화되어 있습니다 (예를 들어 여러 출구를 당신이 할 수없는 방식으로 접는 것 – 당신은 코드를 넣을 수 없습니다 return)
MSalters

32

메모리 관리는 아이들을 놀라게하는 데 사용되지만 프로그래머가 돌봐야 할 유일한 종류의 리소스입니다. 파일 핸들, 네트워크 연결, OS에서 얻는 기타 리소스를 생각하십시오.

가비지 콜렉션을 지원하는 언어는 일반적으로 이러한 자원의 존재를 무시할뿐만 아니라 소멸자를 제공하지 않아서 올바르게 처리하기가 어렵습니다.

즉, C ++ 개발자의 시간이 메모리 관리에 대해 걱정하는 데 많은 시간을 할애하지 않는 것이 좋습니다. klaim의 답변에서 알 수 있듯이 일단 RAII를 처리하면 나머지는 반사적입니다.


3
특히 HttpWebRequest.GetResponse 누수가 처리하고 GC 언어에서 충돌을 시작하는 방법을 좋아합니다. 리소스가 여전히 누출되어 빨라지기 시작할 때까지 GC는 시원합니다. msdn.microsoft.com/en-us/library/… "주의"를 참조하십시오.
Coder

6
메모리를 리소스로 보려면 +1 레거시 코드 여부는 얼마나 많은 시간을 우리가 큰 소리로 외치다해야합니까 : 메모리 관리가 인 기술 이 아니라 저주 .
aquaherd

4
@Coder 내가 따라 갈지 모르겠다. GC는 어쨌든 리소스를 남용 할 수 있기 때문에 짜증 난다 ..? 나는 C #이 IDisposable을 사용하여 결정 론적 자원을 제공하는 좋은 일을한다고 생각한다.
Max Max

8
@ 맥스 : 가비지 수집 된 경우 사용자 정의 IDisposables를 사용하여 바보 같은 리소스에 대해 걱정하지 않아도됩니다. 자원은 범위를 벗어났습니다. 즉, 정리해야합니다. 그럼에도 불구하고, 나는 여전히 어떤 것이 누출 될 것인지, 어느 것이 유출되지 않을지를 생각하고 추측해야합니다. 우선 GC 언어를 사용해야하는 이유를 능가합니다.
Coder

5
@deadalnix 그들은 finalize구조를 가지고 있습니다 . 그러나 언제 호출되는지 알 수 없습니다. 소켓이나 WebResponse 객체가 소진되기 전에 있습니까? 당신은 당신이 의존해서는 안된다는 기사 finalize를 충분히 찾을 수 있습니다 -정당한 이유가 있습니다.
Dysaster

13

거의 없습니다. COM과 같은 오래된 기술조차도 매우 짧은 시간에 변환 할 표준 포인터에 대한 사용자 정의 삭제기를 작성할 수 있습니다. 예를 들어, std::unique_ptr5 줄의 사용자 지정 삭제기로 COM 참조를 고유하게 유지하도록 변환 할 수 있습니다. 자체 리소스 핸들러를 수동으로 작성해야하더라도 SRP 및 복사 및 스왑과 같은 지식의 보급으로 인해 자원 관리 클래스를 작성하여 영원히 사용할 수 있습니다.

실제로는 공유되고 고유하며 소유권이없는 것이 모두 C ++ 11 컴파일러와 함께 제공되며 오래된 코드에서도 작동하도록 작은 어댑터 만 작성하면됩니다.


1
C ++에 얼마나 많은 기술이 필요합니까? a) 사용자 정의 삭제기를 작성하십시오. b) 사용자 정의 삭제 기가 필요한지 알고 있습니까? 새로운 GC 언어를 선택하고 모든 것을 모른 채 수정하기가 쉬워 보이기 때문에 묻습니다 .C ++에서도 쉽게 얻을 수 있습니까?
Sean McMillan

1
@SeanMcMillan : 사용자 지정 삭제 기는 작성 및 배포가 쉽지 않으며, 제가 언급 한 COM은 모든 COM 유형에 대해 5 줄이며, 현대 C ++에 대한 기본 교육을받은 사람이라면 누구나 익숙 할 것입니다. 놀랍게도 GC가 COM 개체를 수집하지 않기 때문에 GC 언어를 선택할 수 없습니다. 또는 파일 핸들. 또는 다른 시스템에서 얻은 메모리. 또는 데이터베이스 연결. RAII는 그 모든 것을 할 것입니다.
DeadMG

2
"GC 언어를 선택하십시오"라는 말은 Java / C # / Ruby / Perl / Javascript / Python 사이를 뛰어 다니며 모두 동일한 리소스 관리 스타일을 가지고 있음을 의미합니다. 메모리는 대부분 자동이며 다른 모든 것 관리해야합니다. C ++의 관리 도구를 사용하면 메모리와 같은 방식으로 파일 핸들 / db 연결 / 등을 관리 할 수 ​​있으며, 일단 배우면 비교적 간단합니다. 뇌 수술이 아닙니다. 올바르게 이해합니까?
Sean McMillan

3
@SeanMcMillan : 예, 맞습니다. 복잡하지 않습니다.
DeadMG

11

내가 C ++ 프로그래머 였을 때 (오래 전에), 버그를 재현하기 어려운 문제를 해결하려고 할 때 메모리 관리 버그에 대해 오랫동안 걱정했다 .

모뎀 C ++를 사용하면 메모리 관리가 훨씬 덜 문제가되지만 대규모 팀의 모든 사람이 올바르게 사용할 수 있습니다. 비용 / 시간은 얼마입니까?

  • 훈련
  • 메모리 관리 문제를 찾기위한 코드 검토
  • 메모리 관리 문제 디버깅
  • 앱의 한 부분에있는 버그는 앱 과 관련이없는 부분의 메모리 관리 문제로 인한 것일 수 있습니다 .

따라서“ 하고있는 ” 시간을 보내는 것만이 아니라 , 이는 대규모 프로젝트에서 더 큰 문제입니다.


2
일부 C ++ 프로젝트는 잘못 작성된 코드로 인해 메모리 누수를 수정하는 데 절망적이라고 생각합니다. 잘못된 코드가 발생할 것이며, 그렇게되면 다른 사람들의 시간도 많이 걸릴 수 있습니다.
Jeremy Jeremy

@ Jeeremy, C ++에서 C #으로 옮길 때 여전히 잘못 작성된 코드가 많지만 적어도 버그가있는 프로그램의 부분을 찾는 것이 훨씬 쉽다는 것을 알았습니다.
Ian

1
예, 이것이 대부분의 상점이 Java 또는 .NET으로 이전 한 이유입니다. 가비지 콜렉션은 잘못된 코드의 피할 수없는 손상을 완화합니다.
Jeremy Jeremy

1
이상하게도, 우리는 그러한 문제가 없습니다.
David Thornley

1
@DavidThornley, C ++로 UI 코드를 작성하는 데 많은 문제가 있다고 생각합니다. 요즘 대부분의 C ++ 코드는 UI가 아닙니다
Ian

2

나는 boost와 TR1 라이브러리를 많이 사용하며 엄격하지 않은 (새로운 / 삭제) 의미없는 메모리 관리를 비 문제로 만듭니다. 반면에 C ++의 메모리 할당은 저렴하지 않으며, 이러한 멋진 공유 포인터가 생성되는 위치에주의를 기울여야합니다. 작업 공간을 많이 사용하거나 스택 기반 메모리로 작업하게됩니다. 일반적으로 구현 문제가 아니라 주로 디자인 문제라고 말하고 싶습니다.


2

클라이언트로서 얼마나 시간이 걸립니까? 일단 당신이 그것을 끊으면 아주 조금. 컨테이너가 수명과 참조를 관리 할 때 정말 쉽습니다. imo는 수동 참조 계산보다 훨씬 간단하며 컴파일러가 잘 설계된 유형 안전 시스템에서 유효하지 않은 소유권 이전을 수행하지 못하게하는 문서로 사용하는 컨테이너를 고려하면 실제로 투명합니다.

내가 (클라이언트로서) 보낸 대부분의 시간은 다른 API의 유형을 포함하는 데 소비되므로 프로그램의 맥락에서 잘 작동합니다. 예 : 이것은 내 ThirdPartyFont 컨테이너이며 이러한 기능을 지원하며 이러한 방식으로 소멸 및 참조 방식으로 계산 하고이 방식으로 복사하고 구현 합니다. 이러한 구조 중 많은 부분이 제자리에 있어야하며 종종 그것들을 배치하는 것이 논리적 장소입니다. 당신이 그것을 시간으로 포함시킬 것인지 아닌지는 당신의 정의에 달려 있습니다 (어쨌든, 이러한 API와 인터페이스 할 때 구현이 존재해야합니까?).

그 후에는 메모리와 소유권을 고려해야합니다. 낮은 수준의 시스템에서는 훌륭하고 필요하지만 물건을 어떻게 움직여야하는지 구현하는 데 시간과 비계가 필요할 수 있습니다. 이것이 하위 시스템의 요구 사항이므로 고통으로 보지 않습니다. 소유권, 통제 및 책임이 분명합니다.

따라서 불투명 유형을 사용하는 c 기반 API로 전환 할 수 있습니다. 컨테이너를 사용하면 수명 관리 및 이러한 불투명 유형의 복사에 대한 작은 구현 세부 정보를 모두 추상화 할 수 있으므로 리소스 관리가 매우 간단하고 시간, 결함을 절약 할 수 있습니다. 구현을 줄입니다.

이것들을 사용하는 것은 매우 간단합니다-GC에서 오는 문제는 이제 자원의 수명을 고려해야한다는 것입니다. 잘못하면 해결하는 데 많은 시간이 걸릴 수 있습니다. 명백한 평생 관리를 배우고 통합하는 것은 비교가 복잡합니다 (모든 사람에게 해당되는 것은 아님). 그것은 실제 장애물입니다. 수명을 제어하고 좋은 솔루션을 사용하는 것이 편 해지면 리소스 수명을 관리하는 것이 매우 쉽습니다. 어려운 버그가 발생하지 않는 한 그것은 내 하루의 중요한 부분이 아닙니다.

컨테이너 (자동 / 공유 포인터)를 사용하지 않으면 고통을 간청합니다.

내 라이브러리를 구현했습니다. 그것은 소요 나에게 그런 것들을 구현하는 시간이 있지만, 대부분의 사람들은 (일반적으로 좋은 아이디어입니다) 다시 사용합니다.


1

수동으로 메모리를 비우고 파일을 닫는 것과 같은 것을 의미합니까? 그렇다면, 내가 "메모리 관리"뿐만 아니라 "자원 관리"로 일반화하는 경우, 내가 사용했던 대부분의 다른 언어보다 최소 및 일반적으로 더 적습니다. 그런 의미에서, 실제로 C ++은 Java 나 C #보다 수동 리소스 관리가 덜 필요하다고 생각합니다.

주로 리소스 (메모리 또는 기타) 파괴를 자동화하는 소멸자 때문입니다. 일반적으로 C ++에서 수동으로 리소스를 해제 / 파괴 해야하는 유일한 시간은 vlow-level 데이터 구조 (대부분의 사람들이 필요하지 않은 것)를 구현하거나 약간의 시간을 보내는 C API를 사용하는 경우입니다. 수동으로 해제 / 파기 / 폐쇄해야하는 C 리소스를 RAII 준수 C ++ 래퍼로 래핑합니다.

물론 사용자가 이미지 편집 소프트웨어에서 이미지를 닫으라고 요청하면 컬렉션이나 무언가에서 이미지를 제거해야합니다. 그러나이 상황에서 중요한 종류의 "메모리"또는 "리소스"관리로 간주되지 않기를 바랍니다. 그 시점에서 해당 이미지와 관련된 메모리를 해제하려면 모든 언어에서 거의 필요하기 때문입니다. 그러나 다시해야 할 일은 컬렉션에서 이미지를 제거하고 이미지 소멸자가 나머지를 처리하는 것입니다.

한편, Java 또는 C #과 비교할 때 수동으로 파일을 닫고, 소켓을 수동으로 연결 해제하고, 객체 참조를 null로 설정하여 가비지 수집이 가능하도록하는 경우가 많습니다. 수동 메모리가 훨씬 더 많습니다. 당신이 저에게 요구하면 그 언어로 자원 관리. unlock뮤텍스 로커는 뮤텍스가 범위를 벗어날 때 자동으로 그렇게하기 때문에 C ++에서는 종종 수동으로 뮤텍스 가 필요하지 않습니다 . 예를 들어 C ++에서 이와 같은 작업을 수행 할 필요는 없습니다.

System.IO.StreamReader file = new System.IO.StreamReader(path);
try
{
    file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
    ...
}
finally
{
    if (file != null)
        file.Close();
}

C ++에서 파일을 수동으로 닫는 것과 같은 작업을 수행 할 필요가 없습니다. 결과적으로 범위를 벗어나 든 정상 또는 예외적 인 실행 경로인지에 상관없이 범위를 벗어나는 순간 자동으로 종료됩니다. 같은 메모리 관련 리소스와 비슷한 것 std::vector. file.Close()위와 같은 코드 는 종종 finally블록 의 맥락에서 찌그러 질 것 입니다. 이는 C ++에 대한 전체 사고 방식이 자동화 할 때 로컬 리소스를 수동으로 해제해야 함을 나타냅니다.

수동 메모리 관리 측면에서 C에는 최대 값, Java / C #에는 중간 정도의 양, C ++에는 최소값이 필요합니다. 마스터하기에는 매우 어려운 언어이기 때문에 C ++을 사용하는 데 약간 부끄러운 이유가 많이 있지만 메모리 관리가 그중 하나가되어서는 안됩니다. 반대로 나는 실제로 이것이 한 측면에서 가장 쉬운 언어 중 하나라고 생각합니다.

물론 C ++에서는 수동으로 메모리를 할당하고 수동으로 메모리를 확보 operator delete/delete[]하기 위해 호출 할 수 있습니다. 그것은 또한 당신이 좋아하는 C의 기능을 사용할 수 있습니다 mallocfree. 그러나 Stroustrup이 RAII를 초창기 전에 RAII를 옹호하기 시작한 이래로 사람들이 신용을주기 훨씬 전에 쓸모 없게 된 일종의 고대 스타일 코딩 관행입니다. "모던 C ++"이 자원 관리를 자동화한다고 말하는 것이 공정하다고 생각조차하지 않습니다. 왜냐하면 그것이 모든 목적이되어야하기 때문입니다. 그렇지 않으면 실제로 예외 안전을 얻을 수 없습니다. 90 년대 초반 많은 오도 된 개발자들이 C와 마찬가지로 C ++을 객체와 함께 사용하려고했지만 종종 예외 처리를 완전히 무시했지만 결코 그런 식으로 사용되지는 않았습니다. 실제로 항상 사용하려는 방식으로 C ++를 사용하는 경우 메모리 관리는 완전히 자동화되어 있으며 일반적으로 수동으로 처리해야하거나 전혀 처리하지 않아도됩니다.


1
현대 Java에는 finally 블록에서 모든 지저분한 코드를 제거하는 "자원을 사용한 시도"가 있습니다. finally 블록을 가질 필요는 거의 없습니다. 디자이너가 RAII 개념을 복사 한 것 같습니다.
kiwiron

0

팀의 수석 기술 책임자에 따라 다릅니다. 내 회사를 포함한 일부 회사에는 스마트 포 이너라는 개념이 없습니다. 공상으로 간주됩니다. 따라서 사람들은 단순히 모든 장소에서 삭제를 수행하고 2 개월마다 메모리 누수 수정을위한 드라이브가 있습니다. 새로운 삭제 문장이 도처에 도착합니다. 따라서 회사와 그곳에서 일하는 사람들의 종류에 따라 다릅니다.


1
귀하의 환경에 귀하 auto_ptr와 친구 를 사용하지 못하게하는 내용이 있습니까?
Sean McMillan

2
C ++ 코드를 작성하지 않는 기업과 같은 소리, 당신은 C. 쓰고있어
gbjbaanb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.