어떤 상황에서 Java가 C++보다 훨씬 느립니까?
Q: 어떤 상황에서 Java가 C++보다 훨씬 느립니까?
답변: Ben Maurer:
이 질문에 답하려면 먼저 문제를 속도 저하의 여러 원인으로 나누어야 합니다.
가비지 컬렉터. 이것은 '양날의 검'이다. 프로그램이 "대부분의 개체는 젊은 세대에서 죽습니다" 모델을 따르는 경우 가비지 수집기는 매우 유익합니다(조각화가 적고 캐시 지역성이 향상됨). 그러나 프로그램이 이 모델을 따르지 않으면 JVM은 힙 메모리를 회수하는 데 많은 리소스를 소비하게 됩니다.
대형 물체. Java에서는 모든 객체에 vtable 포인터가 있지만 C++에서는 POD 구조를 사용할 때 추가 오버헤드가 없습니다. 또한 모든 Java 개체를 잠글 수 있습니다. 구현은 JVM에 따라 달라지며, 객체에 추가 필드를 추가해야 할 수도 있습니다. 큰 객체 == 더 적은 수의 객체를 캐시합니다 == 속도가 느립니다. (한편, Java 7에서는 압축된 포인터에 64비트 레코드를 사용하는데, 이것이 문제의 일부입니다.
인라인 객체가 부족합니다. Java에서는 모든 클래스가 포인터입니다. C++에서는 객체가 될 수 있습니다. 다른 개체와 함께 할당하거나 스택에 할당하면 캐시의 위치가 향상되어 동적 메모리 할당의 오버헤드가 줄어듭니다. Java에서는 개체를 로컬 코드로 컴파일하면 많은 오버헤드가 발생할 수 있습니다. 클라이언트의 C++ 코드를 자주 호출해야 하는 경우에는 많은 오버헤드가 추가됩니다. 예를 들어 문자열은 Java에서 비효율적인 추상화이며 XML 구문 분석기를 작성하려는 경우(char[ 없음) ]), JVM에서 할당한 추가 공간으로 인해 속도가 느려집니다. 거의 모든 함수 호출은 가상 함수 호출이지만 대부분의 경우 JVM은 이 문제를 해결할 수 없으며 🎜> 고급 컴파일이 부족합니다. 기능과 어셈블리로 변환하는 기능 어셈블리의 이점을 누릴 수 있는 코드를 작성하면 Java가 제대로 수행되지 않을 수 있습니다.
내 생각에 가장 큰 문제는 가비지 수집입니다. 대용량 메모리의 전체 GC는 Java와 C++ 간의 격차가 발생하는 가장 큰 이유 중 하나입니다. 또한 프로그램의 작업 세트가 L2 캐시 외부에 배치되면 대형 개체, 인라인 개체 부족 등과 같은 문제가 발생할 수 있습니다. 비효율적인 강제 추상화 및 플랫폼 기능도 속도 저하를 일으킬 수 있지만 이는 일반적으로 잘 작성된 Java 코드 베이스를 사용하는 경우에만 발생합니다. 일반적으로 큰 문제는 아닙니다
A: Todd Lipcon
기본적으로 Ben Maurer의 의견에 동의합니다(안녕 Ben!). 몇 가지 작은 차이점이 있습니다.
최신 JVM에서 이스케이프 분석은 할당이 (a) 로컬 함수 또는 (b) 로컬 스레드에서 절대로 이스케이프되지 않을 때 작동합니다. 즉, 할당에 잠금이 필요하지 않은 경우 일반적으로 자체 스택에서 수행됩니다. 두 경우 모두 단순한 "포인터 범프" 할당입니다. 이는 C의 스택 할당과 동일합니다.
번역자 참고 사항:
이스케이프 분석은 다음을 참조하는 컴파일 최적화 기술입니다. 포인터의 동적 범위를 분석하는 방법입니다. 객체에 대한 포인터가 여러 메서드나 스레드에 의해 참조되는 경우 포인터가 이스케이프된다고 말합니다.
Java 힙의 메모리를 범프한다고 가정합니다. 절대적으로 규칙적이며, 사용된 메모리는 모두 한쪽에 배치되고, 사용 가능한 메모리는 반대쪽에 배치되며, 할당된 메모리는 분할 지점을 나타내는 표시로 중앙에 배치됩니다. 객체의 크기와 동일한 거리만큼 여유 공간에 대한 포인터를 할당하는 방법을 "포인터 충돌"이라고 합니다.
이스케이프 분석 없이도 젊은 세대의 할당은 포인터 충돌을 통해 스레드 로컬 할당 버퍼(TLAB)에서 이루어지며 동기화가 필요하지 않습니다. 따라서 Java의 작은 개체 할당은 C 언어로 구현된 malloc() 메서드보다 더 빠른 경우가 있습니다. Google의 tcmalloc과 같은 더 나은 malloc 방법은 유사한 접근 방식을 취합니다. 그러나 C언어는 할당된 객체를 메모리에 재할당할 수 없기 때문에 일부 제한이 있다.
인라인 및 가상 함수에 문제가 있지만 실제로 어떤 경우에는 Java가 C보다 더 나은 성능을 발휘할 수도 있습니다. 특히 C에서는 인라인 처리가 런타임이 아닌 컴파일 타임에 이루어지기 때문에 동적 연결을 통한 인라인 처리를 구현할 수 없습니다. Java는 컴파일 중에 클래스의 실제 구현을 아직 사용할 수 없는 경우에도 다양한 클래스나 라이브러리의 경계를 넘어 함수를 동적으로 인라인할 수 있습니다. 많은 작업에서 이 접근 방식은 항상 가상 테이블을 호출해야 하는 C++ 가상 함수 호출보다 더 효율적입니다. JIT 컴파일러는 이전에 동적 속성이 손실된 경우(예: 새 클래스가 로드된 경우) 인라인 최적화를 지능적으로 취소할 수 있습니다.
GCC의 새 버전은 이 영역에서 "전체 프로그램 최적화" 또는 "링크 타임 최적화"라고 하는 몇 가지 최적화 기능을 제공합니다. 이를 통해 프로젝트 범위 내의 개체 파일 전체에 인라인을 적용할 수 있습니다. 그러나 기본적으로 동적 연결(예: 인라인을 통한 zlib 호출 등)을 통한 인라인 구현은 허용되지 않습니다. 많은 대규모 프로젝트는 표준 라이브러리의 기능을 코드에 복사하여 구현됩니다.

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다

Docker 환경을 사용할 때 Docker 환경에 Extensions를 설치하기 위해 PECL을 사용하여 오류의 원인 및 솔루션. 종종 일부 두통이 발생합니다 ...

C에서 숯 유형은 문자열에 사용됩니다. 1. 단일 문자를 저장하십시오. 2. 배열을 사용하여 문자열을 나타내고 널 터미네이터로 끝납니다. 3. 문자열 작동 함수를 통해 작동합니다. 4. 키보드에서 문자열을 읽거나 출력하십시오.

캡슐은 3 차원 기하학적 그림이며, 양쪽 끝에 실린더와 반구로 구성됩니다. 캡슐의 부피는 실린더의 부피와 양쪽 끝에 반구의 부피를 첨가하여 계산할 수 있습니다. 이 튜토리얼은 다른 방법을 사용하여 Java에서 주어진 캡슐의 부피를 계산하는 방법에 대해 논의합니다. 캡슐 볼륨 공식 캡슐 볼륨에 대한 공식은 다음과 같습니다. 캡슐 부피 = 원통형 볼륨 2 반구 볼륨 안에, R : 반구의 반경. H : 실린더의 높이 (반구 제외). 예 1 입력하다 반경 = 5 단위 높이 = 10 단위 산출 볼륨 = 1570.8 입방 단위 설명하다 공식을 사용하여 볼륨 계산 : 부피 = π × r2 × h (4

Spring Boot는 강력하고 확장 가능하며 생산 가능한 Java 응용 프로그램의 생성을 단순화하여 Java 개발에 혁명을 일으킨다. Spring Ecosystem에 내재 된 "구성에 대한 협약"접근 방식은 수동 설정, Allo를 최소화합니다.

언어의 멀티 스레딩은 프로그램 효율성을 크게 향상시킬 수 있습니다. C 언어에서 멀티 스레딩을 구현하는 4 가지 주요 방법이 있습니다. 독립 프로세스 생성 : 여러 독립적으로 실행되는 프로세스 생성, 각 프로세스에는 자체 메모리 공간이 있습니다. 의사-다일리트 레딩 : 동일한 메모리 공간을 공유하고 교대로 실행하는 프로세스에서 여러 실행 스트림을 만듭니다. 멀티 스레드 라이브러리 : PTHREADS와 같은 멀티 스레드 라이브러리를 사용하여 스레드를 만들고 관리하여 풍부한 스레드 작동 기능을 제공합니다. COROUTINE : 작업을 작은 하위 작업으로 나누고 차례로 실행하는 가벼운 다중 스레드 구현.

스택은 Lifo (마지막으로, 첫 번째) 원칙을 따르는 데이터 구조입니다. 다시 말해서, 우리가 스택에 추가하는 마지막 요소는 제거 된 첫 번째 요소입니다. 우리가 스택에 요소를 추가 (또는 푸시) 할 때, 그것들은 상단에 배치됩니다. 즉, 무엇보다도

C35의 계산은 본질적으로 조합 수학이며, 5 개의 요소 중 3 개 중에서 선택된 조합 수를 나타냅니다. 계산 공식은 C53 = 5입니다! / (3! * 2!)는 효율을 향상시키고 오버플로를 피하기 위해 루프에 의해 직접 계산할 수 있습니다. 또한 확률 통계, 암호화, 알고리즘 설계 등의 필드에서 많은 문제를 해결하는 데 조합의 특성을 이해하고 효율적인 계산 방법을 마스터하는 데 중요합니다.
