디시인사이드 갤러리

갤러리 이슈박스, 최근방문 갤러리

갤러리 본문 영역

러스트도 정작 고속 로직 짜려면 unsafe 떡칠해야됨

프갤러(14.56) 2025.04.12 22:53:47
조회 63 추천 0 댓글 0

그런데 rust처럼 메모리 접근 제한이 엄격한 언어에서는 OS레벨 수준의 고속 할당자 같은 걸 어떻게 만들 수 있는 거야?



코딩 파트너

안녕하세요! 코딩 파트너입니다. Rust처럼 메모리 접근 제한이 엄격한 언어에서도 OS 레벨 수준의 고속 할당자를 만드는 것은 충분히 가능하며, Rust의 강력한 기능들을 활용하여 안전하고 효율적으로 구현할 수 있습니다.


Rust의 메모리 안전성은 주로 소유권(Ownership), 빌림(Borrowing), **수명(Lifetimes)**이라는 세 가지 핵심 규칙을 통해 컴파일 시점에 보장됩니다. 이러한 규칙들은 개발자가 명시적으로 unsafe 블록을 사용하지 않는 한, 데이터 레이스, 댕글링 포인터, 이중 해제 등의 메모리 안전성 문제를 원천적으로 방지합니다.


그렇다면 OS 레벨의 메모리 할당과 같이 시스템 자원에 직접 접근하고 포인터를 조작해야 하는 작업은 어떻게 Rust의 안전성 규칙 안에서 이루어질까요? 핵심은 unsafe 블록과 **안전한 추상화(Safe Abstraction)**를 사용하는 것입니다.


1. unsafe 블록의 사용:


Rust에서는 안전성 규칙을 위반할 수 있는 연산 (원시 포인터 dereference, FFI 호출 등)은 unsafe 키워드로 둘러싸인 블록 내에서만 허용됩니다.

OS 레벨의 메모리 할당자는 결국 시스템 호출(malloc, free 등)을 통해 운영체제에 메모리 할당 및 해제를 요청하고, 이 과정에서 원시 포인터를 직접 다루게 됩니다. 따라서 Rust로 이러한 기능을 구현하려면 unsafe 블록이 불가피하게 사용됩니다.

예시:


Rust


use std::alloc::{GlobalAlloc, Layout, System};

use std::ptr;


struct MyAllocator;


unsafe impl GlobalAlloc for MyAllocator {

    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {

        // OS 레벨의 메모리 할당 시스템 호출 (예: malloc)

        let ptr = libc::malloc(layout.size());

        if ptr.is_null() {

            ptr::null_mut()

        } else {

            ptr as *mut u8

        }

    }


    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {

        // OS 레벨의 메모리 해제 시스템 호출 (예: free)

        libc::free(ptr as *mut libc::c_void)

    }

}


#[global_allocator]

static GLOBAL: MyAllocator = MyAllocator;


fn main() {

    let layout = Layout::new::<[u32; 10]>();

    unsafe {

        let ptr = std::alloc::alloc(layout);

        if !ptr.is_null() {

            (ptr as *mut [u32; 10]).write([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

            println!("{:?}", * (ptr as *mut [u32; 10]));

            std::alloc::dealloc(ptr, layout);

        }

    }

}

위의 예시 코드에서 MyAllocator는 GlobalAlloc 트레잇을 구현하여 사용자 정의 전역 할당자를 정의합니다. alloc과 dealloc 메서드 내부에서는 libc 크레이트를 통해 C 표준 라이브러리의 malloc과 free 함수를 호출하며, 이 과정은 unsafe 블록으로 감싸져 있습니다.


2. 안전한 추상화 (Safe Abstraction):


핵심적인 부분에서 unsafe를 사용하더라도, Rust의 강력한 타입 시스템과 추상화 기능을 활용하여 안전한 인터페이스를 제공하는 것이 중요합니다.

고속 할당자를 구현할 때, 내부적으로 원시 포인터를 다루더라도 외부에서는 안전한 Rust 타입 (예: Vec, Box)을 통해 메모리를 관리하도록 설계할 수 있습니다.

RAII (Resource Acquisition Is Initialization) 패턴을 활용하여 메모리 할당과 해제를 객체의 생명주기에 묶어 자동으로 관리하도록 구현할 수 있습니다. 이는 개발자가 명시적으로 메모리 해제를 신경 쓰지 않아도 안전하게 메모리를 사용할 수 있도록 합니다.

예시 (간략화):


Rust


struct MyMemoryBlock {

    ptr: *mut u8,

    size: usize,

}


impl MyMemoryBlock {

    fn new(size: usize) -> Self {

        unsafe {

            let ptr = libc::malloc(size);

            if ptr.is_null() {

                panic!("Memory allocation failed");

            }

            MyMemoryBlock { ptr: ptr as *mut u8, size }

        }

    }


    fn as_slice(&self) -> &[u8] {

        unsafe { std::slice::from_raw_parts(self.ptr, self.size) }

    }


    fn as_mut_slice(&mut self) -> &mut [u8] {

        unsafe { std::slice::from_raw_parts_mut(self.ptr, self.size) }

    }

}


impl Drop for MyMemoryBlock {

    fn drop(&mut self) {

        unsafe {

            libc::free(self.ptr as *mut libc::c_void);

        }

    }

}


fn main() {

    let mut block = MyMemoryBlock::new(1024);

    block.as_mut_slice()[0] = 10;

    println!("{}", block.as_slice()[0]);

    // block이 스코프를 벗어나면 drop 메서드가 호출되어 메모리가 자동으로 해제됩니다.

}

위의 예시에서 MyMemoryBlock 구조체는 원시 포인터를 내부적으로 관리하지만, 외부에서는 안전한 as_slice와 as_mut_slice 메서드를 통해 메모리 영역에 접근할 수 있도록 추상화했습니다. 또한 Drop 트레잇을 구현하여 MyMemoryBlock 인스턴스가 스코프를 벗어날 때 자동으로 free를 호출하도록 보장합니다.


결론적으로, Rust는 unsafe 블록을 통해 필요한 저수준 연산을 허용하면서도, 안전한 추상화 메커니즘을 제공하여 OS 레벨의 고속 할당자와 같이 메모리 안전성이 중요한 시스템 프로그래밍 작업을 안전하고 효율적으로 수행할 수 있도록 지원합니다. Rust의 타입 시스템과 소유권 규칙은 개발자가 unsafe 블록의 사용을 최소화하고, 안전한 인터페이스를 설계하도록 유도하여 전반적인 코드 안정성을 높이는 데 기여합니다.


혹시 Rust에서 사용자 정의 할당자를 구현하는 더 구체적인 방법이나 성능 최적화 전략에 대해 궁금하신 점이 있으신가요? 언제든지 질문해주세요.






제시해준 예시는 기본적인 부분이고 c++로 구현하는 고속 할당자는 미리 청크로 관리하는 메모리에 주소만 지정해서 new로 반환해주는 경우가 많자나 그런 걸 rust로도 개발할 수 있어?



코딩 파트너

안녕하세요! 코딩 파트너입니다. 아주 좋은 질문입니다. C++에서 성능 최적화를 위해 미리 청크(chunk)로 메모리를 관리하고 주소만 반환하는 고속 할당자 패턴은 Rust에서도 충분히 그리고 안전하게 개발할 수 있습니다. Rust의 unsafe 블록과 안전한 추상화 기능을 활용하면 C++과 유사한 성능 특성을 가지면서도 메모리 안전성을 보장하는 사용자 정의 할당자를 만들 수 있습니다.


Rust로 청크 기반 고속 할당자 개발:


C++의 아이디어를 Rust로 구현하는 기본적인 단계는 다음과 같습니다.


청크 관리 구조체 정의: 미리 할당된 메모리 청크들을 관리하기 위한 구조체를 정의합니다. 이 구조체는 청크의 시작 주소, 크기, 그리고 현재 사용 가능한 블록들을 추적하는 자료 구조 (예: 연결 리스트, 비트맵)를 포함할 수 있습니다.


메모리 청크 초기화: 프로그램 시작 시 또는 필요에 따라 unsafe 블록 내에서 OS로부터 큰 덩어리의 메모리를 할당받아 청크 관리 구조체에 등록합니다.


블록 할당 로직: alloc 메서드 내에서 청크 관리 구조체를 확인하여 사용 가능한 블록이 있는지 찾습니다. 사용 가능한 블록이 있다면 해당 블록의 주소를 반환하고, 해당 블록이 사용 중임을 표시합니다. 이 과정에서 포인터 조작이 필요하므로 unsafe 블록을 사용하게 됩니다.


블록 해제 로직: dealloc 메서드에서는 해제할 메모리 주소를 받아 청크 관리 구조체 내에서 해당 블록을 다시 사용 가능 상태로 표시합니다. 이 과정에서도 포인터 조작이 필요할 수 있습니다.


안전한 인터페이스 제공: unsafe 블록 내에서 포인터를 직접 다루지만, 외부에서는 안전한 Rust 타입과 메서드를 통해 할당된 메모리를 사용할 수 있도록 추상화합니다. RAII 패턴을 활용하여 메모리 안전성을 보장하는 것이 중요합니다.


구현 예시 (간략화된 개념):


Rust


use std::alloc::{GlobalAlloc, Layout};

use std::cell::RefCell;

use std::ptr;


const CHUNK_SIZE: usize = 4096;


struct ChunkAllocator {

    chunk_ptr: *mut u8,

    chunk_size: usize,

    // 사용 가능한 블록을 추적하는 자료 구조 (예: 연결 리스트)

    free_list: RefCell<Vec<*mut u8>>,

}


impl ChunkAllocator {

    fn new() -> Self {

        let chunk_ptr;

        unsafe {

            chunk_ptr = libc::malloc(CHUNK_SIZE) as *mut u8;

            if chunk_ptr.is_null() {

                panic!("Failed to allocate chunk");

            }

        }

        ChunkAllocator {

            chunk_ptr,

            chunk_size: CHUNK_SIZE,

            free_list: RefCell::new(vec![chunk_ptr]), // 초기에는 전체 청크가 사용 가능

        }

    }


    // ... (사용 가능한 블록 관리 로직 구현) ...

}


unsafe impl GlobalAlloc for ChunkAllocator {

    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {

        // free_list에서 적절한 크기의 사용 가능한 블록을 찾아서 반환

        // 필요하다면 free_list를 업데이트

        // 포인터 연산은 unsafe 블록 내에서 수행

        ptr::null_mut() // 임시 반환

    }


    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {

        // 해제된 블록을 free_list에 다시 추가

        // 포인터 유효성 검사 등 필요

    }

}


#[global_allocator]

static GLOBAL: ChunkAllocator = ChunkAllocator::new();


fn main() {

    let layout = Layout::new::<u32>();

    unsafe {

        let ptr = std::alloc::alloc(layout);

        if !ptr.is_null() {

            *(ptr as *mut u32) = 123;

            println!("{}", *(ptr as *mut u32));

            std::alloc::dealloc(ptr, layout);

        }

    }

}

위의 코드는 매우 간략화된 개념적인 예시이며, 실제 고속 할당자는 훨씬 더 복잡한 로직을 포함합니다. 하지만 핵심 아이디어는 다음과 같습니다.


ChunkAllocator 구조체는 할당된 메모리 청크와 사용 가능한 블록들을 관리합니다.

alloc과 dealloc 메서드 내에서 unsafe 블록을 사용하여 포인터를 조작하고 메모리 할당/해제 로직을 구현합니다.

GlobalAlloc 트레잇을 구현하여 Rust의 전역 할당자로 사용할 수 있도록 합니다.

안전성 확보:


Rust의 타입 시스템과 소유권 규칙을 통해 다음과 같은 안전성을 확보할 수 있습니다.


댕글링 포인터 방지: 할당된 메모리 블록의 수명을 명확하게 관리하고, 소유권 규칙을 통해 이미 해제된 메모리에 접근하는 것을 방지할 수 있습니다.

이중 해제 방지: 할당된 블록이 여러 번 해제되는 것을 방지하는 로직을 구현할 수 있습니다.

메모리 누수 방지: RAII 패턴을 통해 할당된 메모리가 스코프를 벗어날 때 자동으로 해제되도록 보장할 수 있습니다.

결론적으로, Rust로 C++에서 사용되는 청크 기반 고속 할당자와 유사한 성능 최적화 기법을 안전하게 구현하는 것은 충분히 가능합니다. unsafe 블록을 사용하여 저수준 메모리 조작을 수행하되, Rust의 타입 시스템과 추상화 기능을 활용하여 외부에서는 안전하고 편리하게 메모리를 사용할 수 있도록 설계하는 것이 핵심입니다.


혹시 청크 관리 방식이나 동시성 고려 사항 등 더 구체적인 질문이 있으신가요? 언제든지 편하게 물어보세요.







제시해준 방식도 느려보이는데 c++로 구현하면 청크를 union과 케스팅을 이용해서 메모리와 다음 청크를 가르키는 포인터를 같은 메모리에서 참조하게 할 수 있는데 그러면 할당 비용을 줄이고 속도까지 올릴 수 있거든 이런 걸 rust로도 구현할 수 있어?




코딩 파트너

안녕하세요! 코딩 파트너입니다. C++에서 union과 캐스팅을 사용하여 메모리 청크 내에 데이터와 다음 청크를 가리키는 포인터를 겹쳐 할당함으로써 할당 비용을 줄이고 속도를 높이는 최적화 기법에 대해 말씀해주셨네요. Rust에서도 union과 명시적인 메모리 레이아웃 제어를 통해 unsafe 코드를 사용하여 유사한 최적화를 구현할 수 있습니다.


Rust에서 union과 명시적 레이아웃 활용:


Rust의 union 타입은 C의 union과 유사하게, 여러 필드가 같은 메모리 공간을 공유하도록 허용합니다. 이를 통해 메모리 청크의 시작 부분에 데이터 또는 다음 사용 가능한 청크를 가리키는 포인터를 저장하는 방식을 구현할 수 있습니다.


또한, Rust는 #[repr(C)] 속성을 사용하여 구조체나 union의 메모리 레이아웃을 C와 호환되도록 명시할 수 있으며, #[repr(align(N))] 속성을 사용하여 특정 정렬 요구 사항을 지정할 수도 있습니다.


구현 아이디어:


청크 구조체 정의: union을 사용하여 청크의 시작 부분에 실제 데이터 또는 다음 사용 가능한 청크를 가리키는 *mut Self 포인터를 저장합니다. 구조체는 청크의 크기나 사용 상태 등의 메타데이터를 포함할 수도 있습니다.


청크 풀 관리: 미리 할당된 메모리 영역을 청크 크기로 나누고, union을 활용하여 이들을 연결 리스트 형태로 관리합니다. 초기에는 모든 청크가 "사용 가능" 상태이며, union의 포인터 필드를 사용하여 다음 사용 가능한 청크를 가리키도록 연결합니다.


할당 로직: alloc 요청이 들어오면, 사용 가능한 청크 연결 리스트의 헤드에서 청크를 꺼내고, 해당 청크의 주소를 반환합니다. 이때, 반환된 주소는 union의 데이터 필드를 가리키는 포인터로 캐스팅될 수 있습니다.


해제 로직: dealloc 요청이 들어오면, 해제할 메모리 주소에 해당하는 청크를 찾고, 해당 청크를 사용 가능한 청크 연결 리스트의 헤드에 다시 연결합니다. 이때, union의 포인터 필드를 사용하여 연결 리스트를 업데이트합니다.


Rust 코드 예시 (unsafe 사용):


Rust


use std::alloc::{GlobalAlloc, Layout};

use std::ptr;


const CHUNK_SIZE: usize = 64;


#[repr(C)]

union ChunkHeader {

    data: [u8; CHUNK_SIZE],

    next: *mut ChunkHeader,

}


struct LinkedListAllocator {

    head: ptr::NonNull<ChunkHeader>,

    chunk_count: usize,

}


impl LinkedListAllocator {

    fn new(capacity: usize) -> Self {

        let layout = Layout::from_size_align(CHUNK_SIZE * capacity, CHUNK_SIZE).unwrap();

        let ptr = unsafe { std::alloc::alloc(layout) as *mut ChunkHeader };

        if ptr.is_null() {

            panic!("Failed to allocate memory for allocator");

        }


        let mut current = ptr;

        for i in 0..(capacity - 1) {

            unsafe {

                (*current).next = current.add(1);

                current = current.add(1);

            }

        }

        unsafe {

            (*current).next = ptr::null_mut();

        }


        LinkedListAllocator {

            head: ptr::NonNull::new(ptr).unwrap(),

            chunk_count: capacity,

        }

    }

}


unsafe impl GlobalAlloc for LinkedListAllocator {

    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {

        if layout.size() > CHUNK_SIZE {

            return ptr::null_mut(); // 간단하게 큰 할당은 실패 처리

        }


        let head_ptr = self.head.as_ptr();

        if head_ptr.is_null() {

            return ptr::null_mut();

        }


        let next = (*head_ptr).next;

        let allocated = head_ptr as *mut u8;

        // head를 다음 사용 가능한 청크로 업데이트 (unsafe)

        let head_mut = &mut *(self.head.as_ptr() as *mut *mut ChunkHeader);

        *head_mut = next;


        allocated

    }


    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {

        let header_ptr = ptr as *mut ChunkHeader;

        (*header_ptr).next = self.head.as_ptr();

        // head를 해제된 청크로 업데이트 (unsafe)

        let head_mut = &mut *(self.head.as_ptr() as *mut *mut ChunkHeader);

        *head_mut = header_ptr;

    }

}


#[global_allocator]

static GLOBAL: LinkedListAllocator = LinkedListAllocator::new(10);


fn main() {

    let layout_u32 = Layout::new::<u32>();

    let layout_u64 = Layout::new::<u64>();


    unsafe {

        let ptr1 = std::alloc::alloc(layout_u32);

        if !ptr1.is_null() {

            *(ptr1 as *mut u32) = 123;

            println!("Allocated u32 at: {:?}", ptr1);


            let ptr2 = std::alloc::alloc(layout_u64);

            if !ptr2.is_null() {

                *(ptr2 as *mut u64) = 456;

                println!("Allocated u64 at: {:?}", ptr2);


                std::alloc::dealloc(ptr2, layout_u64);

            }

            std::alloc::dealloc(ptr1, layout_u32);

        }

    }

}

주의 사항:


위 코드는 unsafe 블록을 광범위하게 사용하고 있으며, 메모리 안전성을 개발자가 직접 보장해야 합니다.

정렬(alignment) 요구 사항을 제대로 처리하지 않으면 정의되지 않은 동작(Undefined Behavior)이 발생할 수 있습니다. 실제 구현에서는 Layout의 align() 메서드를 고려하여 청크 크기를 결정하고 메모리 접근 시 주의해야 합니다.

동시성 환경에서는 추가적인 동기화 메커니즘(예: Mutex, AtomicPtr)이 필요할 수 있습니다.

결론:


Rust에서도 union과 명시적인 메모리 레이아웃 제어를 통해 C++에서 사용되는 고속 할당자 최적화 기법을 unsafe 코드를 사용하여 구현할 수 있습니다. 이를 통해 할당 비용을 줄이고 속도를 높일 수 있지만, 메모리 안전성을 개발자가 직접 관리해야 하며, 잠재적인 위험을 충분히 이해하고 주의 깊게 코드를 작성해야 합니다.


안전한 Rust 코드를 유지하면서 유사한 성능 향상을 얻기 위해, 더 높은 수준의 추상화와 안전한 데이터 구조를 사용하는 방법을 고려해볼 수도 있습니다. 예를 들어, Cell이나 UnsafeCell을 사용하여 내부 가변성을 안전하게 관리하거나, 인덱스 기반의 메모리 관리 방식을 통해 포인터 연산을 최소화할 수 있습니다.


어떤 방법을 선택할지는 프로젝트의 성능 요구 사항, 안전성 요구 사항, 그리고 개발팀의 Rust 숙련도에 따라 신중하게 결정해야 합니다.


==================


잼민이 피셜임

추천 비추천

0

고정닉 0

0

댓글 영역

전체 댓글 0
등록순정렬 기준선택
본문 보기

하단 갤러리 리스트 영역

왼쪽 컨텐츠 영역

갤러리 리스트 영역

갤러리 리스트
번호 제목 글쓴이 작성일 조회 추천
설문 소속 연예인 논란에 잘 대응하지 못하는 것 같은 소속사는? 운영자 25/04/21 - -
2845417 ㅆㅇㅆ 빡대가리는 RyuDOG갤로그로 이동합니다. 04.18 50 0
2845416 주인 1명있는 집은 개 줘패도 개가 말 잘들음?? [3] ㅇㅇ(223.38) 04.18 47 0
2845415 ㅆㅇㅆ는 그냥 사주의 표본임 RyuDOG갤로그로 이동합니다. 04.18 63 0
2845414 단순히 돈을 벌고 싶은게 아님. 내가 살고 있는 주변을 내 생각대로 [1] ㅆㅇㅆ(124.216) 04.18 49 0
2845413 내가 취직 안한 이유는 인간이 되기 위해서임 [2] ㅆㅇㅆ(124.216) 04.18 63 0
2845410 IT사업의 본질적 특징은 소비 여력에 직접 영향 받는다는거임 [4] ㅆㅇㅆ(124.216) 04.18 92 0
2845408 IT 시장이 지속적으로 커질 수 있었다면 인력 뽑았음. [2] ㅆㅇㅆ(124.216) 04.18 74 0
2845406 정처기 이론수업 걍 한숨만나온다 [2] 공기역학갤로그로 이동합니다. 04.18 82 0
2845405 나님이 이러다 먼저 AGI 도달하는 거 아닒??? [39] 나트륨찡갤로그로 이동합니다. 04.18 98 0
2845403 그냥 시장 자체가 축소되니까 인력 구조조정용 명분으로 AI가 되는것뿐임. ㅆㅇㅆ(124.216) 04.18 52 0
2845401 세계적인 IT 경제 불황인데, 인력 쳐낼 변명이 없으니 AI독박쓰는거지 ㅆㅇㅆ(124.216) 04.18 98 0
2845396 일본 취업 유학 워홀 여행 오픈톡 ㅇㅇ(106.133) 04.18 41 0
2845394 AI 수익화 문제때문에 해외서는 거품론이 계속 나오는듯 어제 o4 발표회 [4] ㅆㅇㅆ(124.216) 04.18 81 0
2845393 나는 초엔터테인먼트 고수가 될 거읾,,, [6] 나트륨찡갤로그로 이동합니다. 04.18 66 0
2845391 나도 내년부터 딩코 연습할 거임,,,, 나트륨찡갤로그로 이동합니다. 04.18 47 0
2845390 한국의 땅과 건물이 외국인에게 팔려나가고 있다 발명도둑잡기갤로그로 이동합니다. 04.18 50 0
2845388 그런데 생각해보니 괘씸하네 RyuDOG갤로그로 이동합니다. 04.18 49 0
2845385 [이성낙 그림 이야기] 탈춤의 가면에는 우리 문화의 속내가 있다 발명도둑잡기갤로그로 이동합니다. 04.18 36 0
2845383 슬슬 이거 들어봐야겟네여 [1] PyTorch갤로그로 이동합니다. 04.18 62 0
2845382 mvc라는게 restapi랑 매칭되는건 아닌건가 프갤러(211.186) 04.18 38 0
2845380 위챗은 이런건데 [4] RyuDOG갤로그로 이동합니다. 04.18 73 0
2845379 아 새벽 불닭 존나 맛있네 류도그담당(114.202) 04.18 55 0
2845378 아 의뢰자 데이터 오늘 준다해놓고 아직 안줘서 오늘 작업 별로 못했네 [1] ㅆㅇㅆ(124.216) 04.18 56 0
2845376 최후의 MIPS CPU 콘솔 게임기 SF2000 후속 SF3000 발명도둑잡기갤로그로 이동합니다. 04.18 43 0
2845373 인과가 완전히 따로 놀다가 겹쳐야지 [5] RyuDOG갤로그로 이동합니다. 04.18 70 0
2845371 터질게 터졌네 ㅋㅋ 프갤러(125.177) 04.18 58 0
2845370 의도가 너무 뻔한 것도 아무런 재미가 없음 RyuDOG갤로그로 이동합니다. 04.18 56 0
2845369 본인과 같은 페이스로 맞춰주고 있는건데 [1] 류도그담당(114.202) 04.18 76 0
2845368 악쓴다고 자극이 오는게 아님 RyuDOG갤로그로 이동합니다. 04.18 40 0
2845366 회사, 개인 캘린더 따로 쓰시는분? ㅈㅁ(211.227) 04.18 29 0
2845365 난 이쯤되면 눈물이 나오려고 함 [3] 류도그담당(114.202) 04.18 79 0
2845364 에어팟 변기에 빠트렸는데 [2] 아스카영원히사랑해갤로그로 이동합니다. 04.18 60 0
2845363 중국 시스템이라면 위챗 아이디로 RyuDOG갤로그로 이동합니다. 04.18 46 0
2845361 애초에 위챗엔 왜 집착할까 RyuDOG갤로그로 이동합니다. 04.18 44 0
2845360 이악물고 글쓴거 보이니 귀엽네 [2] RyuDOG갤로그로 이동합니다. 04.18 59 0
2845358 공식 반국가세력 폭로 발명도둑잡기갤로그로 이동합니다. 04.18 52 0
2845356 아하하하,,, 아하하하하,,, 프붕이들? 싸우는구나?? 나트륨찡갤로그로 이동합니다. 04.18 47 0
2845354 그러니까 그 주장 동의함 ㅇㅇ [1] 류도그담당(114.202) 04.18 127 0
2845353 러스트도 레이블링 되네? [1] 프갤러(110.8) 04.18 65 0
2845352 일본 탈 이모티콘에 있는데 우리 탈은 못 넣나? 발명도둑잡기갤로그로 이동합니다. 04.18 34 0
2845350 20대 후반 고졸인데 주제에 맞게 살아야 하나요 [5] 프갤러(220.88) 04.18 94 0
2845349 사람이라는게 말하는거에서 컴플렉스가 나옴 [8] RyuDOG갤로그로 이동합니다. 04.18 103 0
2845348 이케아 가방으로 만든 한복, 스웨덴 SNS에서 화제 발명도둑잡기갤로그로 이동합니다. 04.18 35 0
2845347 아이유도 아줌마 되가노 [5] 아스카영원히사랑해갤로그로 이동합니다. 04.18 97 0
2845346 쟤 봐바 얼마나 귀여움? [5] 류도그담당(114.202) 04.18 104 0
2845345 사실 귀여울수 밖에 없지 RyuDOG갤로그로 이동합니다. 04.18 41 0
2845341 왜 자꾸 나한텐 겁내는지 모르겠다 [8] 류도그담당(114.202) 04.18 92 0
2845340 나도 류도그같은 저능아는 댓삭해야겠다 ㅆㅇㅆ(124.216) 04.18 50 0
2845339 야레야레. 또 정치싸움인데수? 와타치가 딱 정해주는데스 프갤러(110.8) 04.17 44 0
2845338 ㅆㅇㅆ는 개인적으로 엄청 귀엽다 생각듬 [2] RyuDOG갤로그로 이동합니다. 04.17 71 0
뉴스 사랑보다 음악? 지드래곤, 열애설 속에서도 ‘신곡 몰입’ 디시트렌드 04.25
갤러리 내부 검색
제목+내용게시물 정렬 옵션

오른쪽 컨텐츠 영역

실시간 베스트

1/8

뉴스

디시미디어

디시이슈

1/2