이 블로그를 읽기 전에 먼저 클라이언트 상태에 대한 소개를 읽어보시기를 강력히 권장합니다. 국가의 예술 1부.
2부에서는 클라이언트 상태에서 객체 관리가 어떻게 작동하는지에 대한 세부 사항을 살펴보겠습니다. 매우 추상적인 개념을 다루므로 이 글을 읽는 동안 따뜻한 음료와 두뇌에 좋은 간식을 가까이 두는 것이 좋습니다(흥미로운 객체 관리 아이디어의 경우, 저는 칩을 먹는 것을 선호합니다).
1. 가비지 콜렉션이란 무엇이고 왜 필요한가요?
애플리케이션을 모델링하는 동안 객체를 생성하고, 커밋하고, 롤백하고, 삭제합니다. UI에서 이러한 객체를 표시하고, 마이크로플로우와 나노플로우로 전달하고, 수정하거나, 사용자 정의 위젯에서 작업할 수 있습니다. 작업하는 객체 중 일부는 지속 가능하고 일부는 지속 불가능합니다. 지속 불가능한 객체는 항상 메모리에 있으므로 데이터베이스에 저장되지 않습니다. 또한 새로운 지속 가능한 객체를 커밋할 수 없습니다. 그러면 메모리에 있으므로 효과적으로 지속 불가능해집니다.
일반적인 사용자 세션 동안 사용자는 수십 개의 페이지를 방문하여 수 시간 동안 애플리케이션을 사용하여 여러 객체(지속 가능 또는 지속 불가능)를 만듭니다. 이러한 객체는 클라이언트 상태의 일부가 되어 브라우저 메모리 공간을 차지하므로 시간이 지남에 따라 앱 속도가 느려질 수 있습니다. Mendix 개발자, 애플리케이션에서 생성하지만 커밋하지 않은 모든 객체를 제거할 필요는 없으며, 성능이 저하되지 않고도 앱이 계속 작동합니다. 이것이 어떻게 가능할까요? 무엇이 Mendix 사용자가 10페이지 전에 만든 비지속성 객체는 어떻게 하나요? 지속성 객체에 대한 변경은 어떻게 하나요?
가비지 수집 메커니즘은 이런 질문에 대한 답입니다.

따라서 Mendix 클라이언트는 객체와 상태의 변경 사항을 분석하고 더 이상 필요하지 않은 경우 제거합니다. 이 프로세스의 목표는 메모리에 보관되는 상태를 최소화하는 것입니다. Mendix 앱에 필요한 객체는 아래에 자세히 설명한 몇 가지 기준에 따라 결정됩니다.
2. 가비지 수거는 언제 이루어집니까?
내 동네에서는 대개 화요일 아침입니다. Mendix 앱, 가비지 수집은 앱을 사용할 때 백그라운드에서 발생합니다. 정기적으로 시작되어 모든 객체와 상태의 변경 사항을 분석하고 더 이상 필요하지 않다고 식별된 객체나 변경 사항을 제거합니다.
3. 가비지 수집이 일어나는 것을 볼 수 있나요?
상태 검사 단축키를 사용할 수 있습니다(컨트롤 + 알트 + G) 클라이언트 상태를 검사하고 가비지 수집을 볼 수 있습니다. 그러나 수집될 객체를 보려면 약간의 운이 필요합니다. 종종 수집이 발생하기 전에 수집이 발생합니다. 가비지 수집이 아직 시작되지 않았기 때문에 수집될 객체를 여기서 볼 수 있습니다.

단 몇 초 만에 이 물체는 더 이상 보이지 않게 됩니다.
가비지 수집이 발생할 때 어떤 객체가 제거되는지 확인하기 위해 특수 설정을 활성화할 수도 있습니다. 이렇게 하려면 새 데이터 섹션 logCleanupStatistics: true재산 도조 구성 귀하의 애플리케이션에 구성된 개체 테마/인덱스.html 파일. 코드는 다음과 같아야 합니다.
dojoConfig = {
baseUrl: "mxclientsystem/dojo/",
cacheBust: "{{cachebust}}",
rtlRedirect: "index-rtl.html",
data: {
"logCleanupStatistics": true
}
};
이 섹션을 추가하면 가비지 수집이 발생할 때마다 정보 메시지가 추가됩니다.

면책 조항: 위에 언급된 구성은 공개되지 않으며 사전 통지 없이 변경 또는 삭제될 수 있습니다.
4. 가비지 수집은 어떻게 작동합니까?
이제 애플리케이션에서 생성되거나 로드된 불필요한 객체와 변경 사항이 클라이언트 상태에서 제거되어 애플리케이션이 빠르게 계속 실행될 수 있다는 것을 알게 되었습니다. 하지만 이것이 어떻게 작동할까요?
그 질문에 대한 개념적 답변은 간단합니다. Mendix 클라이언트는 주어진 시간에 어떤 구성 요소에 객체가 필요한지 알아야 합니다. 필요하지 않으면 상태에서 제거할 수 있습니다. 그리고 Mendix 객체는 연결을 통해 하나 이상의 객체를 참조할 수 있습니다(또는 참조될 수 있음). Mendix 클라이언트는 종속된 객체도 추적해야 합니다.
이러한 개념이 실제로 어떻게 작동하는지 자세히 살펴보겠습니다. Mendix 고객.
5. 구독
구독 가비지 수집의 핵심입니다. 구독 시스템은 다음의 하위 시스템입니다. Mendix 클라이언트를 사용하면 변경 사항이 발생할 때마다 알림을 요청할 수 있습니다. Mendix 객체 또는 해당 속성입니다. 사용자 정의 위젯을 위한 간단한 API처럼 보이지만 실제로는 Mendix 클라이언트는 종종 구독을 내부적으로 사용합니다. 다음은 몇 가지 내부 사용 사례입니다.
- 데이터 뷰가 객체를 로드할 때마다 로드된 객체를 구독하여 특정 상황(예: 객체가 삭제될 때)에 대한 알림을 받을 수 있습니다.
- 대부분의 입력 위젯은 작업 중인 객체에 대한 업데이트를 받기 위해 구독에 의존합니다. 이런 방식으로 다른 곳에서 값이 변경될 때마다 값을 업데이트할 수 있습니다. Dojo 위젯은 종종 객체를 수동으로 구독합니다. 그러나 플러그형 위젯 구독은 다음에 의해 처리되므로 이렇게 할 필요가 없습니다. Mendix 고객.
- 따라서 Mendix 클라이언트는 페이지의 조건부 가시성 및 편집 가능성 규칙에 대한 객체를 구독하므로 관련 객체나 속성이 변경될 때 조건을 다시 평가합니다.
- 매개변수가 있는 텍스트 위젯은 객체를 구독합니다. 텍스트 위젯은 템플릿 값이 연결을 초과하면 모든 중간 객체를 구독하므로 위젯은 연결이 변경될 때마다 업데이트해야 한다는 것을 알고 있습니다.
구독은 가비지 수집 메커니즘에 의해 입력으로 처리되어 구독된 객체가 앱에 필요하고 수집되어서는 안 된다는 것을 표시합니다. 즉, 구성 요소나 위젯이 여전히 해당 객체를 사용하거나 필요로 한다는 것입니다.
따라서 Mendix 클라이언트는 또한 알림 콜백을 사용하지 않고도 주어진 순간에 UI에 표시되지 않는 객체를 구독합니다. 이는 다음을 나타내는 방법입니다. Mendix 클라이언트는 해당 객체를 필요로 합니다. 다음은 이러한 동작의 몇 가지 예입니다.
-
표현하는 객체 $현재사용자 $현재세션 항상 구독됩니다 Mendix 클라이언트의 경우 앱을 사용하는 동안만 유효하며 언제든지 애플리케이션에서 필요할 수 있습니다.
참고: $현재세션 보안상의 이유로 객체는 클라이언트로 다시 전송되지 않지만 Mendix 클라이언트가 여전히 구독하고 있습니다. 그 이유는 아래에서 설명하겠습니다.
-
데이터 그리드의 데이터 소스 마이크로플로는 데이터 그리드가 단일 페이지에 표시할 수 있는 것보다 더 많은 객체를 반환할 수 있습니다. 이러한 객체는 클라이언트 상태의 일부가 됩니다. Mendix 클라이언트는 모든 객체를 구독하여 가비지 수집으로 인해 클라이언트 상태에서 객체가 실수로 제거되는 것을 방지합니다.
-
매개변수가 있는 페이지가 닫히면 가비지 수집은 매개변수 객체를 클라이언트 상태에서 제거할 수 있습니다(해당 객체가 더 이상 필요하지 않다고 가정). 이러한 페이지 매개변수는 비지속성 객체일 수 있으며, 이는 제거하면 영원히 액세스할 수 없게 됨을 의미합니다. 하지만 사용자는 브라우저의 뒤로 가기 버튼을 사용하여 돌아갈 수 있으므로 매개변수 객체는 상태를 유지해야 합니다. 그래서 Mendix 클라이언트는 마지막 5개 페이지의 페이지 매개변수 객체를 구독하므로 가비지 수집에서 해당 객체가 제거되지 않습니다.
5.1 객체가 주에 보관되는 이유를 알 수 있습니까?
때때로 특정 객체가 상태에 유지되는 이유를 확인하려면 다음을 사용할 수 있습니다. 컨트롤 + 알트 + G 바로가기. 아래 예에서, 예술가 객체는 현재 페이지의 위젯에 의해 구독됩니다. 때때로 볼 수 있습니다. null로 항목 구독됨위젯 배열입니다. 즉, 이들은 다음에서 구독됩니다. Mendix 클라이언트 내부 또는 사용자 정의 위젯에서:

그러므로 구독된 객체는 구독되는 동안 상태에 보관되어야 함이 분명합니다.
그게 다야?
6. 도달 가능성의 중요성
앞서 언급했듯이 구독된 객체만 유지하는 것만으로는 충분하지 않습니다. Mendix 클라이언트는 연관성을 고려해야 합니다. 다음은 지속 불가능한 Mendix 호출 된 개체 객체 A 클라이언트 상태 내부:

이 객체는 구독되지 않으므로 가비지 수집이 발생할 때 상태에서 제거될 수 있습니다.
또 다른 객체를 추가해 보겠습니다. 비지속성 객체라는 객체입니다. 객체 B:

두 객체 모두 구독되지 않았으므로 클라이언트 상태에서 제거될 수 있습니다.
이제 상상해보세요 객체 A 연관성이 있고, 다음을 참조합니다. 객체 B 그 가치는 다음과 같습니다:

이 상황은 아무것도 변경하지 않습니다. 두 객체 모두 구독되지 않았기 때문에 클라이언트 상태에서 제거될 수 있습니다.
여기에 객체 A 를 사용하여 구독됩니다 mx.데이터.구독 API(주변의 붉은 빛에 주목하세요) 객체 A):

이 상황에서 두 객체는 모두 상태에 보관되어야 합니다. 왜?
객체 A 구독되어 있으므로 가비지 수집 메커니즘이 구독된 객체를 제거하지 않으므로 수집되어서는 안 됩니다.
객체 B 구독하지 않았지만 그렇다고 해서 수집이 가능하다는 의미는 아닙니다. 객체 A 그것을 참조합니다. 수용하는 마이크로 흐름을 고려하십시오. 객체 A 매개변수로. 이 마이크로흐름 내부에서, 객체 B 로 검색됩니다 활동 검색 Association Retrieve 유형을 사용합니다. 가비지 수집이 제거되면 객체 B 상태에서는 이 마이크로흐름이 그것을 검색할 수 없습니다.
따라서 가비지 수집도 이를 고려하여 유지해야 합니다. 객체 B 클라이언트 상태에서. 다음과 같은 이유로 이렇게 해야 합니다.
- 객체 B "도달 가능" 객체 A: 연관되어 있습니다. 마이크로플로우나 나노플로우에서 검색 활동은 그것에 도달할 수 있습니다. 객체 A.
- 객체 B 비지속성이므로 마이크로플로우에서 검색 활동으로 데이터베이스에서 로드할 수 없습니다. 지속성 엔터티(커밋됨)인 경우 마이크로플로우가 애플리케이션 데이터베이스에서 검색할 수 있습니다.
믹스에 새로운 객체를 추가해 보겠습니다. 다음과 같은 일이 발생해야 합니다. 객체 C 가비지 수거는 언제 이루어지나요?

객체 C 또한 도달할 수 있기 때문에 주에 보관해야 합니다. 객체 A -> 객체 B -> 객체 C.
또한 가능합니다 객체 A 두 개의 다른 객체를 동일한 연관의 값으로 참조할 수 있습니다. 어떻게 이런 일이 일어날 수 있을까요? 상상해보세요. 객체 A ~을 언급하는 협회와 함께 헌신합니다. 객체 B. 동일한 연관성을 지적할 때 객체 D 약속하지 않고도 이 협회에 "변화"를 도입합니다. 이 경우, 객체 A 동일한 연결에 대해 커밋된 값과 변경된 값을 모두 알고 있습니다.

가비지 수집은 이 사례를 고려하고 두 가지 모두를 유지합니다. 객체 B 객체 C 주에 따라 두 곳 모두에서 접근이 가능하기 때문에 객체 A.
위의 모든 예는 비지속성 객체와 관련이 있습니다. 지속성 객체를 믹스에 추가해 보겠습니다. 이들은 밝은 파란색 배경으로 표현됩니다.

가비지 수집이 발생할 때 각 지속형 객체에 어떤 일이 일어나는지 살펴보겠습니다.
객체 B 다음과 같은 이유로 수집되어서는 안 됩니다:
- 따라서 (뉴) 이름 끝에 접미사가 붙으면 아직 커밋되지 않았음을 나타내므로 객체가 지속 불가능한 것처럼 동작합니다. 메모리에서만 찾을 수 있습니다.
- 에서 참조되었습니다 객체 A, "도달 가능"으로 표시합니다. 참조되지 않았다면 가비지 수집이 클라이언트 상태에서 제거했을 수 있습니다.
객체 C 다음과 같은 이유로 수집되어서는 안 됩니다:
- 따라서
**이름 끝에 있는 것은 커밋되지 않은 속성/연관성 변경 사항이 있음을 나타냅니다. 이러한 변경 사항은 메모리에 저장될 때까지만 유지됩니다. 객체 C 커밋되거나 롤백됩니다. - 에서 참조되었습니다 객체 A, "도달 가능"으로 표시합니다. 참조되지 않았다면 가비지 수집이 클라이언트 상태에서 제거했을 수 있습니다.
객체 D 다음과 같은 이유로 수집될 수 있습니다:
- 커밋된 객체입니다(없음) (뉴) 접미사).
- 또한 변경 사항이 포함되어 있지 않습니다.
**(이름 뒤에 붙은 이름).
즉 객체 D 커밋되지 않은 속성 값을 포함하지 않으며 필요할 때마다 앱의 데이터베이스에서 찾을 수 있습니다. 따라서 가비지 수집 메커니즘은 참조되는 경우에도 클라이언트 상태에서 제거합니다. 객체 A.
객체 E 구독된 객체에서 참조되지 않기 때문에 수집될 수 있습니다. 즉, 전혀 액세스할 수 없습니다. 가비지 수집은 커밋되지 않은 속성/연관 변경 사항을 포함하여 클라이언트 상태에서 이 객체를 제거할 수 있습니다. 해당 객체에 더 이상 도달할 수 없으므로 객체를 제거하는 것이 안전합니다.
이전 섹션에서 우리는 다음을 언급했습니다. $현재세션 (시스템.세션)는 항상 구독됩니다 Mendix 클라이언트이지만 결코 상태로 끝나지 않습니다. 이제 이유를 추측할 수 있습니다. 상태에 참조하는 객체가 있을 수 있습니다. $현재세션, 따라서 그것으로부터 "도달 가능"합니다. 그래서 그들은 또한 주에 보관될 수도 있습니다.
7. 결론
위의 설명을 바탕으로 가비지 수집 프로세스를 아래와 같이 더욱 요약할 수 있습니다.
가비지 수집은 상태에 있는 모든 구독된 객체에서 시작하여 종속성 그래프를 구축하여 연결을 통해 모든 "도달 가능한" 객체를 찾습니다. 이 그래프를 분석하여 각 객체와 (존재하는 경우) 클라이언트 상태에서의 변경 사항을 유지하거나 삭제할지 결정합니다.
7.1 국가에 보관되는 물건은 무엇인가?
- 구독된 모든 객체는 상태에 보관됩니다.
- 구독된 객체에서 "도달 가능한" 모든 객체는 다음 범주 중 하나에 속하는 경우 보관됩니다.
- 비영구적 객체는 데이터베이스에서 찾을 수 없으므로,
- 생성되었지만 아직 앱의 데이터베이스에 없기 때문에 커밋되지 않은 영구 객체입니다.
- 커밋되었지만 변경 사항을 포함하는 영구 객체. 변경 사항이 아직 데이터베이스에 없지만 마이크로 흐름에 필요할 수 있음.
7.2 어떤 객체가 상태에서 제거됩니까?
- 구독된 객체에서 도달할 수 없는 객체는 삭제됩니다. 이러한 객체는 종종 사용자가 방문한 이전 페이지에서 온 것입니다.
- 구독된 객체에서 여전히 도달 가능하지만 상태가 데이터베이스와 동일한 객체는 삭제됩니다. 이 사례는 데이터베이스에 커밋되고 변경 사항이 없는 지속 가능한 객체에 적용됩니다. 객체가 필요한 경우 데이터베이스에서 로드할 수 있습니다.
위의 설명을 읽은 후, 당신은 약간 무기력함을 느낄 수도 있습니다.

그럼 설명은 그만하고, 배운 것을 연습해 봅시다!
8. 가비지 콜렉션 게임
이전에 그래픽으로 가비지 수집 메커니즘을 설명했습니다. 이제 게임을 해서 메커니즘을 이해하는지 확인해 보겠습니다. 게임의 시나리오는 GC 메커니즘에 대한 내부 단위 테스트에서 나왔습니다. 정답을 맞힐 수 있는지 봅시다!
게임은 간단합니다. 아래에서 클라이언트 상태의 표현을 볼 수 있으며, 범례는 위와 같습니다. 다음은 예입니다.

그래픽을 통해 다음과 같은 사항을 확인할 수 있습니다. 개체 1:
- 지속적인 엔터티(파란색 배경)입니다.
- 구독됨(주변에 붉은색 빛)
- 아직 데이터베이스에 커밋되지 않았습니다(이름 끝에 "(new)"가 있음)
- 변경 사항이 포함되어 있습니다. (
**(이름의 끝에)
이 사례를 보고 나서 궁금한 점이 생길 수 있습니다. "새로운" 객체는 변경이 가능할까요? 객체가 생성될 때 해당 속성은 도메인 모델에서 정의할 수 있는 "기본" 값을 유지하기 때문에 가능합니다. 이러한 기본값은 속성의 현재 "커밋된" 값이 되고, 이에 대한 모든 변경 사항은 상태에 저장됩니다.
객체는 연결을 통해 서로를 참조할 수도 있습니다.

위에서 볼 수 있듯이 개체 1 값이 설정된 연결이 있습니다. 개체 2. 이 게임에서는 연관의 이름이나 기수가 중요하지 않으므로 지정되지 않습니다. 이 화살표는 다음을 나타냅니다. 개체 2 를 사용하여 액세스할 수 있습니다 활동 검색 마이크로흐름을 사용하여 협회 검색 유형.
게임에는 7개의 레벨이 있습니다. 각 레벨은 가비지 수집이 발생하기 전의 "클라이언트 상태"의 현재 상태를 나타냅니다. 목표는 가비지 수집이 발생할 때 상태의 어떤 객체를 보관하고 어떤 객체를 상태에서 제거할지 결정하는 것입니다. 그런 다음 "답변 보기"를 클릭하여 결과를 볼 수 있습니다. 그런 다음 다음 레벨로 이동할 수 있습니다.
게임을 시작하지!
게임을 즐기셨기를 바랍니다! 이제 어떻게 하는지 이해하셨으니 Mendix 클라이언트가 상태를 정리하는 경우 가비지 수집을 염두에 두고 더 나은 앱을 모델링하기 위한 몇 가지 단서는 다음과 같습니다.
9. 모범 사례: 모델링하는 동안 가비지 수집을 염두에 두기
9.1 데이터 소스에서 너무 많은 객체를 반환하지 마십시오
수천 개의 객체를 반환하는 마이크로플로우 소스가 있는 목록 뷰를 상상해 보세요. 모든 객체는 상태에 보관되는 반면, 목록 뷰는 페이징 구성에 따라 주어진 시간에 작은 부분만 표시할 수 있습니다. 이 경우는 나노플로우 데이터 소스와 연관 데이터 소스에도 해당합니다. 이 접근 방식 대신, 대용량 데이터 세트에 매우 최적화된 XPath나 데이터베이스 데이터 소스를 사용해 보세요. 현재 페이지에 표시할 수 있는 데이터만 로드합니다.
9.2 큰 엔터티를 작은 엔터티로 분할
큰 객체를 사용하면 앱의 상태 크기가 커집니다. 큰 객체 전체는 변경 사항이 하나뿐이거나 속성 중 하나에 대해서만 구독된 경우에도 메모리에 저장됩니다. 이러한 객체를 분할하면 가비지 수집에 도움이 될 수 있으며, 특히 지속 불가능한 객체의 경우 더욱 그렇습니다. 이런 방식으로 가비지 수집 알고리즘은 위에서 언급한 조건을 충족하는 경우 사용되지 않는 작은 객체를 제거할 수 있습니다.
9.3 "별 객체"를 생성하지 마십시오
"별 객체"는 수백 개의 다른 객체에서 참조되는 객체입니다. 예를 들어, 검색 결과 객체가 있고 500개가 있습니다 검색 결과 항목 그것을 언급하면서, 검색 결과 별 객체가 됩니다. 둘 중 하나에 대한 구독이 있는 경우 검색 결과 또는 어떤 검색 결과 항목 객체, 모든 객체는 상태에 보관될 수 있습니다. 이 패턴은 모든 객체가 지속 불가능하거나 변경 사항을 포함하는 경우 종종 문제가 됩니다.
이러한 개체로 작업해야 하는 경우 해당 개체를 수동으로 커밋하거나 삭제하거나 연결 값을 별 개체로 설정해야 합니다. 빈 사용한 후에요.
9.4 개발 중 주 크기 확인
사용 컨트롤 + 알트 + G 상태의 크기를 확인하는 단축키. 상태의 내용을 확인하는 것은 특히 큰 페이지에서 작업할 때 중요합니다. 예를 들어, 사용자 정의 위젯에서 구독 취소를 잊었기 때문에 객체가 거기에 남아 있는 것을 볼 수 있습니다.
9.5 과도한 상태에 대한 런타임 로그 확인
따라서 Mendix 클라이언트는 상태의 필수 부분을 런타임 요청에 보내고 클라이언트에서 보낸 개체 수가 특정 임계값을 초과하면 경고가 기록됩니다. 이러한 경고가 표시되면 해당 페이지를 다시 방문하여 상태에 많은 개체가 보관되는 이유를 조사해야 합니다.
이 글을 읽고 도움이 되셨으면 좋겠습니다. 의견, 질문 또는 일반적인 칭찬이 있으시면 😉 저에게 연락하세요 여기에서 확인하세요.