> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK 수명 주기

> 메모리 후크, Core, 서비스 구성을 포함하여 PlayFab Services C SDK를 올바른 순서로 초기화, 구성 및 종료합니다.

이 페이지에서는 PlayFab Services SDK의 전체 시작 및 종료 시퀀스를 다룹니다. 모든 타이틀은 동일한 상위 수준 패턴을 따릅니다: 선택적 후크 구성, Core 초기화, 서비스 구성 생성, Services 초기화, 작업 수행, 그리고 역순으로 종료.

## 초기화 시퀀스

초기화에는 네 단계가 있습니다. 첫 번째는 선택 사항이고 나머지 세 단계는 필수입니다.

```
PFMemSetFunctions (optional)  →  PFInitialize  →  PFServiceConfigCreateHandle  →  PFServicesInitialize
```

### 1단계: 사용자 지정 메모리 후크 설정(선택 사항)

타이틀이 사용자 지정 메모리 할당자를 사용하는 경우, 다른 PlayFab API보다 먼저 [**PFMemSetFunctions**](/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions)를 호출하세요. 이렇게 하면 모든 SDK 메모리 할당이 사용자의 자체 `alloc` 및 `free` 콜백을 통해 라우팅됩니다.

```cpp theme={null}
PFMemoryHooks hooks{};
hooks.alloc = MyAllocFunction;
hooks.free = MyFreeFunction;
HRESULT hr = PFMemSetFunctions(&hooks);
```

<Info>
  [**PFMemSetFunctions**](/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions)는 [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize)보다 먼저 호출해야 합니다. 후크가 설정된 후에는 다시 호출할 수 없습니다.
</Info>

사용자 지정 메모리 관리가 필요 없다면 이 단계를 건너뛰세요. SDK는 기본 할당 루틴을 사용합니다.

### 2단계: PlayFab Core 초기화

[**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize)는 HTTP 계층 및 백그라운드 작업 큐를 포함하여 SDK의 전역 상태를 설정합니다. 정확한 시그니처는 플랫폼에 따라 다릅니다.

#### Windows, Linux, iOS 및 macOS

```cpp theme={null}
HRESULT hr = PFInitialize(nullptr); // Uses a default threadpool queue
```

백그라운드 작업을 처리할 큐를 제어하려면 \_\_XTaskQueueHandle\_\_을 전달합니다. 기본 스레드풀 큐를 사용하려면 `nullptr`을 전달합니다.

#### Android

Android에서는 SDK가 libHttpClient를 초기화할 수 있도록 Java VM과 애플리케이션 컨텍스트도 제공해야 합니다:

```cpp theme={null}
HRESULT hr = PFInitialize(nullptr, javaVm, applicationContext);
```

<Note>
  \_\_PFInitialize\_\_를 명시적으로 호출하지 않으면, [**PFServicesInitialize**](/services/playfab/api-references/c/pfservices/functions/pfservicesinitialize)가 내부적으로 기본 매개변수로 호출합니다. 대부분의 타이틀에서는 이것으로 충분합니다. 그러나 \_\_PFMemSetFunctions\_\_를 통해 사용자 지정 메모리 후크를 사용하는 경우, \_\_PFInitialize\_\_를 직접 호출해야 **합니다**. 그렇지 않으면 [**PFServicesInitialize**](/services/playfab/api-references/c/pfservices/functions/pfservicesinitialize)가 메모리 후크가 적용되기 전에 Core를 초기화하며, SDK는 기본 할당 루틴을 사용하게 됩니다.
</Note>

### 3단계: 서비스 구성 생성

[**PFServiceConfigCreateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigcreatehandle)은 SDK가 대상으로 삼을 PlayFab 타이틀과 엔드포인트를 지정하는 핸들을 생성합니다. 두 값 모두 [Game Manager](https://developer.playfab.com)에서 확인할 수 있습니다.

```cpp theme={null}
PFServiceConfigHandle serviceConfigHandle{ nullptr };
HRESULT hr = PFServiceConfigCreateHandle(
    "https://ABCDEF.playfabapi.com",    // API endpoint from Game Manager
    "ABCDEF",                           // Title ID from Game Manager
    &serviceConfigHandle);
```

반환된 \_\_PFServiceConfigHandle\_\_은 이후의 모든 로그인 호출에 필요합니다.

### 4단계: PlayFab Services 초기화

\_\_PFServicesInitialize\_\_는 Core 위에 Services 계층(Inventory, Leaderboards, Friends 등)을 설정합니다.

#### Windows, Linux, iOS 및 macOS

```cpp theme={null}
HRESULT hr = PFServicesInitialize(nullptr);
```

이 매개변수는 향후 사용을 위해 예약되어 있으므로 `nullptr`을 전달합니다.

#### Android

Android에서는 Java VM과 애플리케이션 컨텍스트를 포함하는 **HCInitArgs** 구조체를 전달합니다:

```cpp theme={null}
HRESULT hr = PFServicesInitialize(nullptr, initArgs);
```

이 호출이 성공한 후 SDK가 준비됩니다. 플레이어를 로그인하고 서비스 호출을 할 수 있습니다.

## PFServiceConfigHandle 수명 주기

\_\_PFServiceConfigHandle\_\_은 참조 카운트가 있는 핸들입니다. SDK가 참조 카운팅을 통해 내부 수명을 관리하지만, 사용자가 소유한 모든 핸들을 닫을 책임은 사용자에게 있습니다.

| 함수                                                                                                                                | 설명                                                                                                                                                                                    |
| --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**PFServiceConfigCreateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigcreatehandle)       | 새 핸들을 생성합니다. 초기 참조 카운트는 1입니다.                                                                                                                                                         |
| [**PFServiceConfigDuplicateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigduplicatehandle) | 참조 카운트를 증가시키고 두 번째 핸들을 반환합니다. 두 핸들 모두 독립적으로 닫아야 합니다.                                                                                                                                  |
| [**PFServiceConfigCloseHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigclosehandle)         | 참조 카운트를 감소시킵니다. 0에 도달하면 구성이 소멸됩니다.                                                                                                                                                    |
| [**PFServiceConfigGetAPIEndpoint**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggetapiendpoint)   | API 엔드포인트 문자열을 검색합니다. 버퍼 크기를 결정하려면 먼저 [**PFServiceConfigGetAPIEndpointSize**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggetapiendpointsize)를 호출하세요. |
| [**PFServiceConfigGetTitleId**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggettitleid)           | 타이틀 ID 문자열을 검색합니다. 버퍼 크기를 결정하려면 먼저 [**PFServiceConfigGetTitleIdSize**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfiggettitleidsize)를 호출하세요.            |

### 핸들 복제

자체 수명을 관리하는 구성 요소 간에 서비스 구성을 공유해야 하는 경우 [**PFServiceConfigDuplicateHandle**](/services/playfab/api-references/c/pfserviceconfig/functions/pfserviceconfigduplicatehandle)을 사용하세요:

```cpp theme={null}
PFServiceConfigHandle duplicatedHandle{ nullptr };
HRESULT hr = PFServiceConfigDuplicateHandle(serviceConfigHandle, &duplicatedHandle);

// Both handles are now valid and must be closed separately
PFServiceConfigCloseHandle(duplicatedHandle);
PFServiceConfigCloseHandle(serviceConfigHandle);
```

## 종료 시퀀스

종료는 초기화의 역순입니다. Core보다 먼저 Services를 초기화 해제해야 하며, 두 호출 모두 비동기입니다.

```
Close handles  →  PFServicesUninitializeAsync  →  PFUninitializeAsync
```

### 1단계: 열려 있는 모든 핸들 닫기

SDK를 해제하기 전에 소유한 모든 **PFEntityHandle** 및 \_\_PFServiceConfigHandle\_\_을 닫으세요:

```cpp theme={null}
PFEntityCloseHandle(entityHandle);
entityHandle = nullptr;

PFServiceConfigCloseHandle(serviceConfigHandle);
serviceConfigHandle = nullptr;
```

### 2단계: Services 초기화 해제

[**PFServicesUninitializeAsync**](/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync)는 Services 계층을 해제합니다. 계속하기 전에 완료를 기다리세요.

```cpp theme={null}
XAsyncBlock asyncServices{};
HRESULT hr = PFServicesUninitializeAsync(&asyncServices);
hr = XAsyncGetStatus(&asyncServices, true); // Blocking wait
```

### 3단계: Core 초기화 해제

Services 정리가 완료된 후, [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync)를 호출해 Core를 해제합니다:

```cpp theme={null}
XAsyncBlock asyncCore{};
HRESULT hr = PFUninitializeAsync(&asyncCore);
hr = XAsyncGetStatus(&asyncCore, true); // Blocking wait
```

<Note>
  \_\_PFInitialize\_\_를 명시적으로 호출하지 않은 경우 \_\_PFUninitializeAsync\_\_를 건너뛸 수 있습니다. 이 경우 [**PFServicesUninitializeAsync**](/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync)가 Core 정리를 자동으로 처리합니다. 그러나 \_\_PFInitialize\_\_를 직접 호출한 경우 [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync)를 직접 호출해야 합니다.
</Note>

## 전체 예제

이 예제는 Windows 타이틀에서 초기화부터 종료까지 전체 수명 주기를 보여줍니다:

```cpp theme={null}
#include <playfab/services/PFServices.h>

void RunPlayFab()
{
    //
    // Optional: set custom memory hooks
    //
    PFMemoryHooks hooks{};
    hooks.alloc = MyAllocFunction;
    hooks.free = MyFreeFunction;
    HRESULT hr = PFMemSetFunctions(&hooks);

    //
    // Initialize Core
    //
    hr = PFInitialize(nullptr);

    //
    // Create a service configuration
    //
    PFServiceConfigHandle serviceConfigHandle{ nullptr };
    hr = PFServiceConfigCreateHandle(
        "https://ABCDEF.playfabapi.com",
        "ABCDEF",
        &serviceConfigHandle);

    //
    // Initialize Services
    //
    hr = PFServicesInitialize(nullptr);

    //
    // Log in a player (Windows example using XUser)
    //
    PFAuthenticationLoginWithXUserRequest request{};
    request.createAccount = true;
    request.user = userHandle;

    XAsyncBlock asyncLogin{};
    hr = PFAuthenticationLoginWithXUserAsync(serviceConfigHandle, &request, &asyncLogin);
    hr = XAsyncGetStatus(&asyncLogin, true);

    size_t bufferSize{};
    hr = PFAuthenticationLoginWithXUserGetResultSize(&asyncLogin, &bufferSize);

    std::vector<char> loginResultBuffer(bufferSize);
    PFAuthenticationLoginResult const* loginResult{};
    PFEntityHandle entityHandle{ nullptr };
    hr = PFAuthenticationLoginWithXUserGetResult(
        &asyncLogin, &entityHandle,
        loginResultBuffer.size(), loginResultBuffer.data(),
        &loginResult, nullptr);

    //
    // ... make service calls ...
    //

    //
    // Shutdown: close handles first
    //
    PFEntityCloseHandle(entityHandle);
    entityHandle = nullptr;

    PFServiceConfigCloseHandle(serviceConfigHandle);
    serviceConfigHandle = nullptr;

    //
    // Shutdown: uninitialize Services, then Core
    //
    XAsyncBlock asyncServices{};
    hr = PFServicesUninitializeAsync(&asyncServices);
    hr = XAsyncGetStatus(&asyncServices, true);

    XAsyncBlock asyncCore{};
    hr = PFUninitializeAsync(&asyncCore);
    hr = XAsyncGetStatus(&asyncCore, true);
}
```

## 일반적인 실수

| 실수                                                                                                                                                                                                                              | 발생 결과                                                      | 해결 방법                                                                                                                                                                                                     |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize) 이후에 [**PFMemSetFunctions**](/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions) 호출                                  | 호출이 실패합니다. 메모리 후크는 초기화 전에만 설정할 수 있습니다.                     | 프로그램에서 [**PFMemSetFunctions**](/services/playfab/api-references/c/pfplatform/functions/pfmemsetfunctions)를 가장 첫 번째 PlayFab 호출로 옮기세요.                                                                      |
| [**PFServicesUninitializeAsync**](/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync) 전에 [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync) 호출 | 정의되지 않은 동작이 발생합니다. Services가 아직 Core에 의존하는 동안 Core가 해제됩니다. | 항상 Services를 먼저 초기화 해제하고, 완료를 기다린 다음 Core를 초기화 해제하세요.                                                                                                                                                     |
| 명시적 [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize) 이후 [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync) 호출을 잊음                           | Core 리소스가 누수됩니다. 백그라운드 큐와 HTTP 계층이 정리되지 않습니다.              | [**PFInitialize**](/services/playfab/api-references/c/pfcore/functions/pfinitialize)를 호출했다면 [**PFUninitializeAsync**](/services/playfab/api-references/c/pfcore/functions/pfuninitializeasync)를 호출해야 합니다. |
| 비동기 초기화 해제 완료를 기다리지 않음                                                                                                                                                                                                          | 정리가 진행되는 동안 프로세스가 종료되어 크래시 또는 행이 발생할 수 있습니다.               | 완료를 기다리려면 `XAsyncGetStatus(async, true)` 또는 **XAsyncBlock** 콜백을 사용하세요.                                                                                                                                    |
| **PFServiceConfigHandle** 또는 **PFEntityHandle** 누수                                                                                                                                                                              | 참조 카운트가 있는 리소스가 해제되지 않아 정상적인 종료를 방해할 수 있습니다.               | 초기화 해제를 호출하기 전에 생성하거나 복제한 모든 핸들을 닫으세요.                                                                                                                                                                    |

## 참고 항목

* [빠른 시작: Win32](/services/playfab/sdks/c/quickstart-win32)
* [빠른 시작: Windows](/services/playfab/sdks/c/quickstart-gdk)
* [디버그 추적](/services/playfab/sdks/c/tracing)
* [비동기 프로그래밍 모델](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/system/overviews/async-programming-model)


## Related topics

- [엔터티 핸들](/ko/services/playfab/sdks/c/entity-handles.md)
- [멀티플레이어 서버의 수명 주기](/ko/services/playfab/multiplayer/servers/multiplayer-game-server-lifecycle.md)
- [멀티플레이어 서버 빌드의 수명 주기](/ko/services/playfab/multiplayer/servers/multiplayer-build-lifecycle.md)
- [멀티플레이어 서버 빌드 리전의 수명 주기](/ko/services/playfab/multiplayer/servers/multiplayer-build-region-lifecycle.md)
- [PlayFab Services SDK - 이벤트 파이프라인](/ko/services/playfab/sdks/c/event-pipeline/eventpipeline.md)
