const std = @import("std"); const expect = std.testing.expect; // The Zig standard library provides a pattern for allocating memory, // which allows the programmer to choose precisely how memory allocations are done within the standard library // - no allocations happen behind your back in the standard library. // Zig 표준 라이브러리는 메모리 할당 패턴을 하나만 제공하며, // 이를 통해 프로그래머는 표준 라이브러리 내부에서 메모리 할당을 어떻게 할지 선택할 수 있습니다. // 사용자가 모르는 사이에 메모리 할당이 발생하지 않습니다. // The most basic allocator is `std.heap.page_allocator`. // Whenever this allocator makes an allocation, it will ask your OS for entire pages of memory; // an allocation of a single byte will likely reserve multiple kibibytes(`KiB`). // As asking the OS for memory requires a system call, this is also extremely inefficient for speed. // 가장 기본적인 할당자는 `std.heap.page_allocator`입니다. 이 할당자는 메모리를 할당할 때 OS에게 전체 페이지의 메모리를 요청합니다. // 하나의 바이트를 할당하더라도 여러 `키비바이트`(`KiB`)를 예약할 수 있습니다. // OS에게 메모리를 요청하는 것은 시스템 호출을 필요로 하므로, 이는 매우 비효율적입니다. // Here, we allocate 100 bytes as a []u8. // Notice how defer is used in conjunction with a free - this is a common pattern for memory management in Zig. // 여기서는 []u8로 100바이트를 할당합니다. defer와 free가 함께 사용되는 것을 주목하세요. // - 이는 Zig에서 메모리 관리에 일반적인 패턴입니다. test "allocation" { const allocator = std.heap.page_allocator; const memory = try allocator.alloc(u8, 100); defer allocator.free(memory); try expect(memory.len == 100); try expect(@TypeOf(memory) == []u8); } // The `std.heap.FixedBufferAllocator` is an allocator // that allocates memory into a fixed buffer and does not make any heap allocations. // This is useful when heap usage is not wanted, for example, when writing a kernel. // It may also be considered for performance reasons. // - It will give you the error `OutOfMemory` if it has run out of bytes. // 이 할당자는 고정된 버퍼에 메모리를 할당하며, 힙 할당을 하지 않습니다. // 이는 힙 사용을 원하지 않을 때, 예를 들어 커널을 작성할 때 유용합니다. // - 성능 이유로 고려될 수 있습니다. 메모리가 부족할 경우 `OutOfMemory` 오류를 발생시킵니다. test "fixed buffer allocator" { var buffer: [1000]u8 = undefined; var fba = std.heap.FixedBufferAllocator.init(&buffer); const allocator = fba.allocator(); const memory = try allocator.alloc(u8, 100); defer allocator.free(memory); try expect(memory.len == 100); try expect(@TypeOf(memory) == []u8); } // `std.heap.ArenaAllocator` takes in a child allocator and allows you to allocate many times and only free once. // Here, `.deinit()` is called on the arena, which frees all memory. // Using allocator.free in this example would be a no-op (i.e. does nothing). // `std.heap.ArenaAllocator`는 자식 할당자를 포함하고, 여러 번 할당을 할 수 있으며, 한 번에 해제할 수 있습니다. // 여기서, `.deinit()`는 arena 할당자에서 호출하여 모든 메모리를 해제합니다. // 이 예제에서는 `allocator.free`를 사용하면 아무 것도 하지 않습니다(`no-op`). test "arena allocator" { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const allocator = arena.allocator(); _ = try allocator.alloc(u8, 1); _ = try allocator.alloc(u8, 10); _ = try allocator.alloc(u8, 100); // allocator.free(); // no-op, no declaration `allocator.free` at zig-1.15.2` } // alloc and free are used for slices. For single items, consider using create and destroy. // `alloc`과 `free`는 슬라이스에 사용됩니다. 단일 항목에 대해서는 `create`와 `destroy`를 사용하세요. test "allocator create/destroy" { const byte = try std.heap.page_allocator.create(u8); defer std.heap.page_allocator.destroy(byte); byte.* = 128; try expect(byte.* == 128); } // The Zig standard library also has a general-purpose allocator. // This is a safe allocator that can prevent double-free, use-after-free and can detect leaks. // Safety checks and thread safety can be turned off via its configuration struct (left empty below). // Zig's GPA is designed for safety over performance, but may still be many times faster than page_allocator. // Zig 표준 라이브러리에는 일반적인 목적의 할당자도 있습니다. // 이는 이중 free, free 후 사용, 메모리 누수를 방지할 수 있는 안전한 할당자입니다. // 안전성 검사와 스레드 안전성은 구성 구조체를 통해 끌 수 있습니다 (left empty below). // - `std.heap.GeneralPurposeAllocator(.{}){};`, `{}`는 구성 구조체입니다. // Zig의 GPA는 성능보다 안전성을 우선시하도록 설계되었지만, `page_allocator`보다 여러 배 더 빠를 수 있습니다. const print = std.debug.print; test "GPA" { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); defer { const deinit_status = gpa.deinit(); //fail test; can't try in defer as defer is executed after we return if (deinit_status == .leak) expect(false) catch @panic("TEST FAIL"); } const bytes = try allocator.alloc(u8, 100); // const sample_text = "Hello, GPA!"; // for (bytes, 0..) |*byte, i| { // byte.* = @as(u8, sample_text.ptr[i]); // } // bytes[sample_text.len] = @as(u8, 0); // const bytes_slice = bytes[0 .. sample_text.len + 1 :@as(u8, 0)]; // print("bytes: {s}\n", .{bytes_slice}); defer allocator.free(bytes); } // For high performance (but very few safety features!), std.heap.c_allocator may be considered. // This,however, has the disadvantage of requiring linking `Libc`, which can be done with `-lc`. // 높은 성능(하지만 매우 적은 안전성 기능!)을 위해 `std.heap.c_allocator`를 고려할 수 있습니다. // 그러나, `Libc`를 링크해야 하는 단점이 있으며, `-lc`로 수행할 수 있습니다. // Benjamin Feng's talk `What's a Memory Allocator Anyway?` goes into more detail on this topic, // and covers the implementation of allocators. // Benjamin Feng의 토크 `What's a Memory Allocator Anyway?`는 이 주제에 대해 더 자세히 설명하고, // 할당자의 구현을 다룹니다.