Optimal Stack Size Configurations for libfiber Workloads: A Complete Guide

The iqiyi/libfiber library offers three tunable stack configurations—private stacks (default 320 KB), shared stacks (default 1 MB), and fiber pool allocation (typically 64 KB)—that must be matched to your workload’s concurrency level and call depth to prevent memory exhaustion or stack overflows.

Tuning coroutine stack sizes is essential when scaling libfiber applications from hundreds to tens of thousands of并发 fibers. The library exposes granular control over memory allocation through specific APIs in cpp/include/fiber/fiber.hpp and c/include/fiber/fiber_base.h, allowing developers to optimize for either I/O-bound high concurrency or CPU-bound deep recursion. This guide maps the source code implementation to practical configuration strategies.

Configuration Methods and Defaults

libfiber provides three distinct mechanisms for controlling stack memory, each defined in specific source files with different default values and use cases.

Private Stack (Per-Fiber Allocation)

The private stack allocates dedicated memory for each coroutine at creation time. In cpp/include/fiber/fiber.hpp lines 55-60, the default size is defined as 320 000 bytes (approximately 312 KB). You specify this through the fiber::start(stack_size, share_stack = false) method in C++ or acl_fiber_create(fn, ctx, size) in the C API.

This mode guarantees isolation between fibers but consumes linear memory relative to your fiber count. A workload with 10 000 fibers will reserve roughly 3 GB of virtual memory using the default 320 KB setting.

Shared-Stack Mode

For massive fiber counts, shared-stack mode allows multiple fibers to time-share a single memory region. The default shared stack size is 1 024 000 bytes (~1 MB), configurable via fiber::set_shared_stack_size() as implemented in cpp/include/fiber/fiber.hpp lines 260-264.

According to c/include/fiber/fiber_base.h lines 31-38, the minimum safe shared stack size must be greater than 1 KB. You activate this mode by passing share_stack = true to acl_fiber_create() or using the go_share(stack_size) macro wrapper defined in cpp/include/fiber/go_fiber.hpp lines 36-46.

Fiber Pool Configuration

The fiber pool API offers a middle ground for managed concurrency. As demonstrated in samples/cxx/fiber_pool/main.cpp lines 15-16, the constructor acl::fiber_pool(pool_min, pool_max, idle_ms, buf, stack, shared) typically uses 64 000 bytes (64 KB) per fiber. This configuration appears in high-throughput benchmarks where the pool manages fiber lifecycle and recycling automatically.

Workload-Specific Recommendations

Selecting the appropriate stack size requires balancing memory constraints against your application’s call depth and concurrency requirements.

High-Concurrency I/O (Echo Servers, Proxies)

For network services handling thousands of connections with shallow callback chains, use 64 KB–128 KB stacks with shared-stack mode enabled. This reduces memory consumption from approximately 3 GB to under 500 MB for 10 000 fibers. The shared-stack approach works because I/O-bound fibers yield frequently and maintain minimal local state.

CPU-Bound Processing (Computation, Parsing)

Deep recursion or heavy C++ object construction requires 256 KB–320 KB private stacks. Keep share_stack = false to prevent stack corruption when multiple fibers contend for space. This configuration trades memory efficiency for safety in complex call graphs.

Mixed Workloads

Applications combining I/O waits with moderate processing should start with 128 KB–256 KB private stacks. Monitor production memory usage; if you encounter pressure, migrate to shared-stack mode only after verifying your call depth remains shallow (fewer than 20 nested function calls).

Benchmarking and Embedded Systems

The fiber_pool sample demonstrates that 64 KB stacks yield maximum QPS in stress tests. For embedded devices with severe memory constraints, shared stacks as small as 32 KB–64 KB are viable, provided you validate that your application’s maximum recursion depth fits within the allocated space.

Implementation Examples

Setting a Custom Private Stack

#include "fiber/fiber.hpp"

class worker_fiber : public acl::fiber {
protected:
    void run() override {
        // Perform work with guaranteed stack isolation
    }
};

int main() {
    // Allocate 200 KB private stack (below default 320 KB)
    worker_fiber* fb = new worker_fiber();
    fb->start(200000, false);
    acl::fiber::schedule();
    return 0;
}

This creates a fiber with 200 KB of dedicated stack space, suitable for medium-depth call chains.

Enabling Shared-Stack Mode for Massive Concurrency

#include "fiber/go_fiber.hpp"

int main() {
    // Configure 512 KB shared stack for all subsequent fibers
    acl::fiber::set_shared_stack_size(512000);
    
    for (int i = 0; i < 10000; ++i) {
        go_share(512000)[i] {
            // Lightweight socket I/O operations
        };
    }
    acl::fiber::schedule();
    return 0;
}

The go_share macro expands to acl::go_fiber(stack, true), enabling time-shared stack usage across all 10 000 fibers.

Configuring a Fiber Pool with Explicit Stack Size

#include <acl-lib/fiber/fiber_pool.hpp>
#include <acl-lib/fiber/wait_group.hpp>

void process_task(acl::wait_group* wg) {
    // Task implementation
    wg->done();
}

int main() {
    // 64 KB stack, non-shared mode for pool workers
    acl::fiber_pool pool(1, 20, 30, 500, 64000, false);
    
    acl::wait_group wg;
    wg.add(100);
    for (int i = 0; i < 100; ++i) {
        pool.exec([i, &wg] { process_task(&wg); });
    }
    wg.wait();
    pool.stop();
    return 0;
}

This matches the high-performance configuration found in samples/cxx/fiber_pool/main.cpp.

Querying Runtime Stack Configuration

size_t current_size = acl::fiber::get_shared_stack_size();
printf("Current shared stack size: %zu bytes\n", current_size);

The implementation in cpp/src/fiber.cpp lines 190-198 handles the attribute retrieval via acl_fiber_attr_getstacksize.

Summary

  • Private stacks default to 320 KB in cpp/include/fiber/fiber.hpp and suit CPU-bound workloads with deep call chains.
  • Shared-stack mode defaults to 1 MB and enables 10 000+ fiber concurrency by time-sharing memory, requiring minimum sizes above 1 KB per fiber_base.h.
  • Fiber pools demonstrate that 64 KB stacks provide optimal throughput in benchmarks when using the acl::fiber_pool constructor.
  • Always validate your application’s maximum recursion depth against the chosen stack size to prevent segmentation faults.

Frequently Asked Questions

What is the default stack size for libfiber coroutines?

The default private stack size is 320 000 bytes (approximately 320 KB) as defined in cpp/include/fiber/fiber.hpp. For shared-stack mode, the default is 1 024 000 bytes (1 MB). These defaults are hardcoded in the C++ wrapper headers but can be overridden via the start() or set_shared_stack_size() APIs.

When should I use shared-stack mode instead of private stacks?

Use shared-stack mode when running more than 10 000 lightweight, I/O-bound fibers where memory conservation outweighs the need for deep recursion. According to the implementation in c/include/fiber/fiber_base.h, the shared stack must be larger than 1 KB, but typical production deployments use 64 KB–512 KB shared regions to reduce memory pressure by 80–90% compared to private allocations.

How does stack size affect memory usage in high-concurrency scenarios?

Each private stack reserves its full size in virtual memory immediately upon fiber creation. With the 320 KB default, 10 000 fibers consume approximately 3 GB of RAM. Switching to a 64 KB shared-stack configuration reduces this to roughly 640 MB total (including the 1 MB shared region), making it feasible to run hundreds of thousands of fibers on standard hardware.

What is the minimum safe stack size for libfiber applications?

The absolute minimum is 1 001 bytes (just above 1 KB) according to the safety check comments in c/include/fiber/fiber_base.h lines 31-38. However, practical deployments should use at least 32 KB for trivial workloads and 64 KB for any production I/O service to accommodate library function calls and exception handling frames without triggering guard-page faults.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →