๐Ÿง _์‹ฌ์ธต_ํƒ๊ตฌ_Memory_Management_Performance

๋ฐœํ–‰: (2025๋…„ 12์›” 29์ผ ์˜ค์ „ 09:00 GMT+9)
12 min read
์›๋ฌธ: Dev.to

Source: Dev.to

(๋ฒˆ์—ญํ•  ํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•ด ์ฃผ์‹œ๋ฉด ํ•œ๊ตญ์–ด๋กœ ๋ฒˆ์—ญํ•ด ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.)

๐Ÿ’ก ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์˜ ํ•ต์‹ฌ ๊ณผ์ œ

ํ˜„๋Œ€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ •๊ธฐ์ ์œผ๋กœ ์„ธ ๊ฐ€์ง€ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ œ์— ์ง๋ฉดํ•ฉ๋‹ˆ๋‹ค:

๋„์ „ ๊ณผ์ œ์ค‘์š”ํ•œ ์ด์œ 
๐Ÿšจ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ํ•ด์ œ๋˜์ง€ ์•Š์€ ๊ฐ์ฒด๊ฐ€ ๊ฒฐ๊ตญ ํž™์„ ๊ณ ๊ฐˆ์‹œ์ผœ ์ถฉ๋Œ์ด๋‚˜ OOM ์˜ค๋ฅ˜๋ฅผ ์ผ์œผํ‚ต๋‹ˆ๋‹ค.
โฐ GC ์ผ์‹œ์ •์ง€Stopโ€‘theโ€‘world ์ผ์‹œ์ •์ง€๋กœ ์ธํ•ด ์š”์ฒญ ์ง€์—ฐ ์‹œ๊ฐ„์ด ์ฆ๊ฐ€ํ•˜๋ฉฐ, ์ด๋Š” ์ง€์—ฐ์— ๋ฏผ๊ฐํ•œ ์„œ๋น„์Šค์—์„œ๋Š” ์šฉ๋‚ฉ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
๐Ÿ“Š ๋ฉ”๋ชจ๋ฆฌ ๋‹จํŽธํ™”๋ฐ˜๋ณต์ ์ธ ํ• ๋‹น/ํ•ด์ œ๋กœ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋‹จํŽธํ™”๋˜์–ด ์บ์‹œ ํšจ์œจ์ด ๊ฐ์†Œํ•˜๊ณ  ์ „์ฒด ์ฒ˜๋ฆฌ๋Ÿ‰์ด ์ €ํ•˜๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“Š ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์„ฑ๋Šฅ ๋น„๊ต

๐Ÿ”ฌ ๋ฉ”๋ชจ๋ฆฌโ€‘์‚ฌ์šฉ ํšจ์œจ์„ฑ ํ…Œ์ŠคํŠธ

์‹œ๋‚˜๋ฆฌ์˜ค: 1โ€ฏ๋ฐฑ๋งŒ ๋™์‹œ ์—ฐ๊ฒฐ, ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐ„ ๋™์ผ ์›Œํฌ๋กœ๋“œ.

Framework๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰GC ์ผ์‹œ์ •์ง€ ์‹œ๊ฐ„ํ• ๋‹น ํšŸ์ˆ˜ํ•ด์ œ ํšŸ์ˆ˜
Hyperlane Framework96โ€ฏMB0โ€ฏms12โ€ฏ54312โ€ฏ543
Rust Standard Library84โ€ฏMB0โ€ฏms15โ€ฏ67215โ€ฏ672
Go Standard Library98โ€ฏMB15โ€ฏms45โ€ฏ23445โ€ฏ234
Tokio128โ€ฏMB0โ€ฏms18โ€ฏ45618โ€ฏ456
Gin Framework112โ€ฏMB23โ€ฏms52โ€ฏ78952โ€ฏ789
Rocket Framework156โ€ฏMB0โ€ฏms21โ€ฏ23421โ€ฏ234
Node Standard Library186โ€ฏMB125โ€ฏms89โ€ฏ45689โ€ฏ456

๐Ÿ“ˆ ๋ฉ”๋ชจ๋ฆฌโ€‘ํ• ๋‹น ์ง€์—ฐ ๋น„๊ต

Frameworkํ‰๊ท  ํ• ๋‹น ์‹œ๊ฐ„P99 ํ• ๋‹น ์‹œ๊ฐ„์ตœ๋Œ€ ํ• ๋‹น ์‹œ๊ฐ„ํ• ๋‹น ์‹คํŒจ์œจ
Hyperlane Framework0.12โ€ฏยตs0.45โ€ฏยตs2.34โ€ฏยตs0โ€ฏ%
Rust Standard Library0.15โ€ฏยตs0.52โ€ฏยตs2.78โ€ฏยตs0โ€ฏ%
Tokio0.18โ€ฏยตs0.67โ€ฏยตs3.45โ€ฏยตs0โ€ฏ%
Rocket Framework0.21โ€ฏยตs0.78โ€ฏยตs4.12โ€ฏยตs0โ€ฏ%
Go Standard Library0.89โ€ฏยตs3.45โ€ฏยตs15.67โ€ฏยตs0.01โ€ฏ%
Gin Framework1.23โ€ฏยตs4.56โ€ฏยตs23.89โ€ฏยตs0.02โ€ฏ%
Node Standard Library2.45โ€ฏยตs8.92โ€ฏยตs45.67โ€ฏยตs0.05โ€ฏ%

๐ŸŽฏ ํ•ต์‹ฌ ๋ฉ”๋ชจ๋ฆฌโ€‘๊ด€๋ฆฌ ๊ธฐ์ˆ  ๋ถ„์„

๐Ÿš€ ์ œ๋กœโ€‘๊ฐ€๋น„์ง€ ์„ค๊ณ„

Hyperlane ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์„ธ ๊ฐ€์ง€ ์ƒ๋ณด์ ์ธ ๊ธฐ๋ฒ•์„ ํ†ตํ•ด ๊ฑฐ์˜ ์ œ๋กœ์— ๊ฐ€๊นŒ์šด ๊ฐ€๋น„์ง€ ์ƒ์„ฑ์„ ๋‹ฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

1๏ธโƒฃ ๊ฐ์ฒดโ€‘ํ’€ ๊ธฐ์ˆ 

// Hyperlane framework's objectโ€‘pool implementation
struct MemoryPool<T> {
    objects:   Vec<T>,
    free_list: Vec<usize>,
    capacity:  usize,
}

impl<T> MemoryPool<T> {
    fn new(capacity: usize) -> Self {
        let objects = Vec::with_capacity(capacity);
        let mut free_list = Vec::with_capacity(capacity);
        for i in 0..capacity {
            free_list.push(i);
        }
        Self { objects, free_list, capacity }
    }

    fn allocate(&mut self, value: T) -> Option<usize> {
        if let Some(index) = self.free_list.pop() {
            if index >= self.objects.len() {
                self.objects.push(value);
            } else {
                self.objects[index] = value;
            }
            Some(index)
        } else {
            None
        }
    }

    fn deallocate(&mut self, index: usize) {
        // Return the slot to the free list
        self.free_list.push(index);
    }
}

2๏ธโƒฃ ์—ฐ๊ฒฐโ€‘ํ•ธ๋“ค๋Ÿฌ ๋ฒ„ํผ (์˜ˆ์‹œ)

use std::collections::HashMap;

struct ConnectionHandler {
    // Preโ€‘allocated read buffer
    read_buffer: Vec<u8>,
    // Preโ€‘allocated write buffer
    write_buffer: Vec<u8>,
    // Preโ€‘allocated header storage
    headers: HashMap<String, String>,
}

impl ConnectionHandler {
    fn new() -> Self {
        Self {
            read_buffer: Vec::with_capacity(8_192),   // 8โ€ฏKB
            write_buffer: Vec::with_capacity(8_192), // 8โ€ฏKB
            headers: HashMap::with_capacity(16),     // space for 16 headers
        }
    }
}

4๏ธโƒฃ ๋ฉ”๋ชจ๋ฆฌโ€‘๋ ˆ์ด์•„์›ƒ ์ตœ์ ํ™”

// Struct layout tuned for cache friendliness
#[repr(C)]
struct OptimizedStruct {
    // Highโ€‘frequency fields grouped together
    id:       u64,          // 8โ€‘byte aligned
    status:   u32,          // 4โ€‘byte
    flags:    u16,          // 2โ€‘byte
    version:  u16,          // 2โ€‘byte
    // Lowโ€‘frequency fields placed at the end
    metadata: Vec<u8>,      // heapโ€‘allocated pointer
}

์„ธ ๊ฐ€์ง€ ๊ธฐ๋ฒ•โ€”๊ฐ์ฒด ํ’€๋ง, ์‚ฌ์ „ ํ• ๋‹น ๋ฒ„ํผ, ๊ทธ๋ฆฌ๊ณ  ์บ์‹œ ์นœํ™”์ ์ธ ๋ ˆ์ด์•„์›ƒโ€”์ด ํ•จ๊ป˜ ์ž‘๋™ํ•˜์—ฌ ํ• ๋‹น์„ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ๋Ÿฐํƒ€์ž„ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์„ ์ตœ์†Œํ™”ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ’ป ๋ฉ”๋ชจ๋ฆฌโ€‘๊ด€๋ฆฌ ๊ตฌํ˜„ ๋ถ„์„

๐Ÿข Node.js ๋ฉ”๋ชจ๋ฆฌโ€‘๊ด€๋ฆฌ ๋ฌธ์ œ

// Example: perโ€‘request allocations in a naive Node.js server
const http = require('http');

const server = http.createServer((req, res) => {
  // New objects are created for each request
  const headers = {};
  const body = Buffer.alloc(1024); // heap allocation

  // V8 GC pauses become noticeable under load
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello');
});

server.listen(60000);

๋ฌธ์ œ ๋ถ„์„

์ฆ์ƒ๊ทผ๋ณธ ์›์ธ
๋นˆ๋ฒˆํ•œ ๊ฐ์ฒด ์ƒ์„ฑ๊ฐ ์š”์ฒญ๋งˆ๋‹ค ์ƒˆ๋กœ์šด headers์™€ body ๊ฐ์ฒด๊ฐ€ ํ• ๋‹น๋˜์–ด V8์˜ ์„ธ๋Œ€๋ณ„ GC์— ์••๋ ฅ์ด ๊ฐ€ํ•ด์ง‘๋‹ˆ๋‹ค.
GCโ€‘์œ ๋ฐœ ์ง€์—ฐ ์ŠคํŒŒ์ดํฌ๋†’์€ ๋™์‹œ์„ฑ ํ•˜์—์„œ GC๊ฐ€ stopโ€‘theโ€‘world ์ผ์‹œ ์ •์ง€๋ฅผ ์ผ์œผ์ผœ ์š”์ฒญ ์ง€์—ฐ์ด ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
๋ฉ”๋ชจ๋ฆฌ ๋‹จํŽธํ™”Buffer์˜ ๋ฐ˜๋ณต์ ์ธ ํ• ๋‹นยทํ•ด์ œ๊ฐ€ ํž™์„ ๋‹จํŽธํ™”์‹œ์ผœ ํ• ๋‹น ์ฒ˜๋ฆฌ๋Ÿ‰์„ ๊ฐ์†Œ์‹œํ‚ต๋‹ˆ๋‹ค.

์™„ํ™” ๋ฐฉ์•ˆ์œผ๋กœ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ์ฒด ํ’€๋ง, ๋ฒ„ํผ ์žฌ์‚ฌ์šฉ, ๋˜๋Š” ์ค‘์š”ํ•œ ๊ฒฝ๋กœ๋ฅผ ๋„ค์ดํ‹ฐ๋ธŒ ํ™•์žฅ์ด๋‚˜ ๋Œ€์ฒด ๋Ÿฐํƒ€์ž„์œผ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

๐Ÿน Go์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ

Go์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋Š” ๋น„๊ต์  ํšจ์œจ์ ์ด์ง€๋งŒ, ์•„์ง ๊ฐœ์„  ์—ฌ์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

package main

import (
	"fmt"
	"net/http"
	"sync"
)

var bufferPool = sync.Pool{
	New: func() interface{} {
		return make([]byte, 1024)
	},
}

func handler(w http.ResponseWriter, r *http.Request) {
	// Use sync.Pool to reduce memory allocation
	buffer := bufferPool.Get().([]byte)
	defer bufferPool.Put(buffer)

	fmt.Fprintf(w, "Hello")
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":60000", nil)
}

์žฅ์  ๋ถ„์„

  • sync.Pool โ€“ ๊ฐ„๋‹จํ•œ ๊ฐ์ฒด ํ’€ ๋ฉ”์ปค๋‹ˆ์ฆ˜.
  • ๋™์‹œ์„ฑ ์•ˆ์ „์„ฑ โ€“ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ๊ฐ€ ๋™์‹œ์— ์‹คํ–‰๋˜์–ด ์ผ์‹œ ์ •์ง€ ์‹œ๊ฐ„์ด ์งง์•„์ง‘๋‹ˆ๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ ์••์ถ•์„ฑ โ€“ Go์˜ ํ• ๋‹น์ž๋Š” ๋น„๊ต์  ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

๋‹จ์  ๋ถ„์„

  • GC ์ผ์‹œ ์ •์ง€ โ€“ ์—ฌ์ „ํžˆ ์ง€์—ฐ ์‹œ๊ฐ„์— ๋ฏผ๊ฐํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์˜ํ–ฅ์„ ์ค๋‹ˆ๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ โ€“ Go ๋Ÿฐํƒ€์ž„์ด ์ถ”๊ฐ€ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.
  • ํ• ๋‹น ์ „๋žต โ€“ ์ž‘์€ ๊ฐ์ฒด ํ• ๋‹น์ด ์™„์ „ํžˆ ์ตœ์ ํ™”๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿš€ Rust์˜ ๋ฉ”๋ชจ๋ฆฌโ€‘๊ด€๋ฆฌ ์žฅ์ 

use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};

fn handle_client(mut stream: TcpStream) {
    // Zeroโ€‘cost abstraction โ€“ memory layout determined at compile time
    let mut buffer = [0u8; 1024]; // Stack allocation

    // Ownership system ensures memory safety
    let response = b"HTTP/1.1 200 OK\r\n\r\nHello";
    stream.write_all(response).unwrap();
    stream.flush().unwrap();

    // Memory automatically released when the function ends
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:60000").unwrap();

    for stream in listener.incoming() {
        let stream = stream.unwrap();
        handle_client(stream);
    }
}

์žฅ์  ๋ถ„์„

  • Zeroโ€‘cost abstractions โ€“ ์ปดํŒŒ์ผ ์‹œ ์ตœ์ ํ™”๊ฐ€ ์ด๋ฃจ์–ด์ง€๋ฉฐ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  • No GC pauses โ€“ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์œผ๋กœ ์ธํ•œ ์ง€์—ฐ์ด ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.
  • Memory safety โ€“ ์†Œ์œ ๊ถŒ ์‹œ์Šคํ…œ์ด ์ปดํŒŒ์ผ ํƒ€์ž„์— ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
  • Precise control โ€“ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์–ธ์ œ ํ• ๋‹น๋˜๊ณ  ํ•ด์ œ๋˜๋Š”์ง€๋ฅผ ์ •ํ™•ํžˆ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋„์ „ ๊ณผ์ œ ๋ถ„์„

  • Learning curve โ€“ ์†Œ์œ ๊ถŒ๊ณผ ๋Œ€์—ฌ ๊ทœ์น™์„ ์ตํžˆ๋Š” ๋ฐ ์‹œ๊ฐ„์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • Compilation time โ€“ ์ˆ˜๋ช…(lifetime) ๋ถ„์„์œผ๋กœ ์ธํ•ด ๋นŒ๋“œ ์‹œ๊ฐ„์ด ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Development efficiency โ€“ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ๊ธฐ๋ฐ˜ ์–ธ์–ด์— ๋น„ํ•ด ๊ฐœ๋ฐœ ํšจ์œจ์„ฑ์ด ๋‚ฎ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Source:

๐ŸŽฏ Production Environment Memory Optimization Practice

๐Ÿช ์ „์ž์ƒ๊ฑฐ๋ž˜ ์‹œ์Šคํ…œ ๋ฉ”๋ชจ๋ฆฌ ์ตœ์ ํ™”

๊ฐ์ฒด ํ’€ ํ™œ์šฉ

// Product information object pool
struct ProductPool {
    pool: MemoryPool,
}

impl ProductPool {
    fn get_product(&mut self) -> Option<ProductHandle> {
        self.pool.allocate(Product::new())
    }

    fn return_product(&mut self, handle: ProductHandle) {
        self.pool.deallocate(handle.index());
    }
}

๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์ „ ํ• ๋‹น

// Shoppingโ€‘cart memory preโ€‘allocation
struct ShoppingCart {
    items: Vec<Product>, // Preโ€‘allocated capacity
    total: f64,
    discount: f64,
}

impl ShoppingCart {
    fn new() -> Self {
        Self {
            items: Vec::with_capacity(20), // Reserve space for 20 products
            total: 0.0,
            discount: 0.0,
        }
    }
}

๐Ÿ’ณ ๊ฒฐ์ œ ์‹œ์Šคํ…œ ๋ฉ”๋ชจ๋ฆฌ ์ตœ์ ํ™”

์ œ๋กœโ€‘๋ณต์‚ฌ ์„ค๊ณ„

use tokio::io::AsyncReadExt;
use std::net::TcpStream;

// A static buffer that lives for the whole program lifetime
static mut PAYMENT_BUFFER: [u8; 4096] = [0; 4096];

async fn process_payment(stream: &mut TcpStream) -> Result<(), std::io::Error> {
    // SAFETY: The buffer is only accessed by this async task.
    let buffer = unsafe { &mut PAYMENT_BUFFER };
    stream.read_exact(buffer).await?;

    // Direct processing, no extra copying
    let payment = parse_payment(buffer)?;
    process_payment_internal(payment).await?;

    Ok(())
}

๋ฉ”๋ชจ๋ฆฌ ํ’€ ๊ด€๋ฆฌ

use once_cell::sync::Lazy;

// A pool that holds up to 10โ€ฏ000 preโ€‘allocated paymentโ€‘transaction objects
static PAYMENT_POOL: Lazy<MemoryPool<PaymentTransaction>> = Lazy::new(|| {
    MemoryPool::new(10_000)
});

๐Ÿ”ฎ ๋ฏธ๋ž˜ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ํŠธ๋ Œ๋“œ

๐Ÿš€ ํ•˜๋“œ์›จ์–ด ์ง€์› ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ

NUMAโ€‘์ธ์‹ ํ• ๋‹น
// NUMAโ€‘aware memory allocation (requires a crate that wraps libnuma)
fn numa_aware_allocate(size: usize) -> *mut u8 {
    let node = get_current_numa_node();
    unsafe { numa_alloc_onnode(size, node) }
}
์ง€์† ๋ฉ”๋ชจ๋ฆฌ
// Simple wrapper for persistentโ€‘memoryโ€‘mapped files
struct PersistentMemory {
    ptr: *mut u8,
    size: usize,
}

impl PersistentMemory {
    fn new(size: usize) -> Self {
        // `pmem_map_file` is a thin wrapper around libpmem
        let ptr = unsafe { pmem_map_file(size) };
        Self { ptr, size }
    }
}

๐Ÿ”ง ์ง€๋Šฅํ˜• ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ

๋จธ์‹ ๋Ÿฌ๋‹ ๊ธฐ๋ฐ˜ ํ• ๋‹น
// A โ€œsmartโ€ allocator that uses a trained model to pick the best strategy
struct SmartAllocator {
    model: AllocationModel,
    history: Vec<AllocationRecord>,
}

impl SmartAllocator {
    fn predict_allocation(&self, size: usize) -> AllocationStrategy {
        self.model.predict(size, &self.history)
    }
}

์œ„ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์€ ํ˜„์žฌ ๊ถŒ์žฅ๋˜๋Š” ํŒจํ„ด(๊ฐ์ฒด ํ’€, ์‚ฌ์ „ ํ• ๋‹น, ์ œ๋กœโ€‘๋ณต์‚ฌ I/O)์„ ๋ณด์—ฌ์ฃผ๋ฉฐ, ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๊ฐ€ ํ•˜๋“œ์›จ์–ด ์ง€์› ๊ธฐ์ˆ ๊ณผ AI ๊ธฐ๋ฐ˜ ํ• ๋‹น ๊ฒฐ์ •์œผ๋กœ ํ–ฅํ•˜๊ณ  ์žˆ์Œ์„ ์—ฟ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŽฏ ์š”์•ฝ

  • Go๋Š” ํŽธ๋ฆฌํ•œ ํ’€๋ง๊ณผ ๋™์‹œ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ์—ฌ์ „ํžˆ ์ผ์‹œ ์ •์ง€ ์‹œ๊ฐ„๊ณผ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • Rust๋Š” GC ์ผ์‹œ ์ •์ง€๋ฅผ ์—†์• ๊ณ  ์„ธ๋ฐ€ํ•œ ์ œ์–ด๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ, ํ•™์Šต ๊ณก์„ ์ด ๊ฐ€ํŒŒ๋ฅด๊ณ  ์ปดํŒŒ์ผ ์‹œ๊ฐ„์ด ๊ธธ์–ด์ง€๋Š” ๋น„์šฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์‹ค์ œ ์‹œ์Šคํ…œ(์ „์ž์ƒ๊ฑฐ๋ž˜, ๊ฒฐ์ œ)์€ ๋‹ค์Œ์œผ๋กœ ์ด์ ์„ ์–ป์Šต๋‹ˆ๋‹ค:
    • ๊ฐ์ฒด ํ’€
    • ์‚ฌ์ „ ํ• ๋‹น
    • ์ œ๋กœ ์นดํ”ผ ์„ค๊ณ„
    • ํ•˜๋“œ์›จ์–ด ์ธ์‹ ์ „๋žต(NUMA, ์ง€์† ๋ฉ”๋ชจ๋ฆฌ)
  • ์ƒˆ๋กœ์šด ํŠธ๋ Œ๋“œ๋Š” ํ•˜๋“œ์›จ์–ด ์ง€์› ํ• ๋‹น ๋ฐ ์›Œํฌ๋กœ๋“œ ํŒจํ„ด์— ์ ์‘ํ•˜๋Š” AI ๊ธฐ๋ฐ˜ ํ• ๋‹น์ž๋ฅผ ํ–ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์‹ฌ์ธต ๋ถ„์„

์ด ๋ถ„์„์„ ํ†ตํ•ด ํ”„๋ ˆ์ž„์›Œํฌ๋งˆ๋‹ค ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๋ฐฉ์‹์— ํฐ ์ฐจ์ด๊ฐ€ ์žˆ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ Hyperlane ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ œ๋กœโ€‘๊ฐ€๋น„์ง€ ์„ค๊ณ„๋Š” ์ธ์ƒ์ ์ž…๋‹ˆ๋‹คโ€”๊ฐ์ฒด ํ’€๊ณผ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์ „ ํ• ๋‹น์„ ํ™œ์šฉํ•˜์—ฌ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ๋ฌธ์ œ๋ฅผ ๊ฑฐ์˜ ์™„์ „ํžˆ ํšŒํ”ผํ•ฉ๋‹ˆ๋‹ค.

  • Rust โ€“ ์†Œ์œ ๊ถŒ ์‹œ์Šคํ…œ์„ ํ†ตํ•ด ๊ฐ•๋ ฅํ•œ ๋ฉ”๋ชจ๋ฆฌ ์•ˆ์ „ ๋ณด์žฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • Go โ€“ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ๊ฐ€ ํŽธ๋ฆฌํ•˜์ง€๋งŒ, ์ง€์—ฐ ์‹œ๊ฐ„์— ๋ฏผ๊ฐํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๊ฐœ์„  ์—ฌ์ง€๊ฐ€ ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ฑ๋Šฅ ์ตœ์ ํ™”์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ์˜ฌ๋ฐ”๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ์ตœ์ ํ™” ์ „๋žต์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์‹œ์Šคํ…œ ์„ฑ๋Šฅ์— ๊ฒฐ์ •์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค. ์ด ๋ถ„์„์ด ๋” ๋‚˜์€ ๊ฒฐ์ •์„ ๋‚ด๋ฆฌ๋Š” ๋ฐ ๋„์›€์ด ๋˜๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.

GitHub: hyperlane-dev/hyperlane

Back to Blog

๊ด€๋ จ ๊ธ€

๋” ๋ณด๊ธฐ ยป

๐Ÿง _์‹ฌ์ธต_ํƒ๊ตฌ_Memory_Management_Performance[20260104084429]

์†Œ๊ฐœ ์—”์ง€๋‹ˆ์–ด๋กœ์„œ ์ˆ˜๋งŽ์€ performanceโ€‘tuning ์‚ฌ๋ก€๋ฅผ ๊ฒฝํ—˜ํ•œ ๋‚˜๋Š” memory management๊ฐ€ webโ€‘application ์„ฑ๋Šฅ์— ์–ผ๋งˆ๋‚˜ ํฐ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š”์ง€ ๊นŠ์ด ์ดํ•ดํ•˜๊ณ  ์žˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋น„๋ฐ€์Šค๋Ÿฌ์šด ์‚ถ: ๊ธฐ์–ต

Ghost Room: ํด๋กœ์ €์™€ ์ฃฝ์ง€ ์•Š์œผ๋ ค๋Š” ๋ณ€์ˆ˜๋“ค์˜ ์ด์•ผ๊ธฐ. ํ‹ฐ๋ชจ์‹œ๊ฐ€ ๋ฉ”์ธ ๋„์„œ๊ด€ ํ™€์—์„œ ๋–จ์–ด์ง„ ์ž‘์€ ๊ฐœ์ธ ์—ฐ๊ตฌ์‹ค์˜ ๋ฌธํ„ฑ์— ์„œ ์žˆ์—ˆ๋‹ค. ๊ทธ๋Š” h...

GC๋Š” ๋А๋ฆฌ์ง€ ์•Š๋‹ค โ€” ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ฐจ์ง€ํ•˜๊ณ  ์žˆ์„ ๋ฟ

Garbage Collection(GC)์€ ํ”„๋ก ํŠธ์—”๋“œ ์—”์ง€๋‹ˆ์–ด๋“ค์ด ์กด์žฌ๋Š” ์•Œ๊ณ  ์žˆ์ง€๋งŒ ๊ฑฐ์˜ ์ƒ๊ฐํ•˜์ง€ ์•Š๋Š” ์ฃผ์ œ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹คโ€”ํ•˜์ง€๋งŒ ๋ฌด์–ธ๊ฐ€๊ฐ€ ๋Š๊ธฐ๊ฑฐ๋‚˜, ๋ฉˆ์ถ”๊ฑฐ๋‚˜, ์‹ ๋น„๋กญ๊ฒŒ ๋А๋ ค์งˆ ๋•Œ๊นŒ์ง€๋Š” ๋ง์ด์ฃ .