惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Archives - TechRepublic
Security Archives - TechRepublic
W
WeLiveSecurity
Hacker News: Ask HN
Hacker News: Ask HN
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Heimdal Security Blog
Help Net Security
Help Net Security
T
Troy Hunt's Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
N
News | PayPal Newsroom
TaoSecurity Blog
TaoSecurity Blog
T
Threat Research - Cisco Blogs
NISL@THU
NISL@THU
G
GRAHAM CLULEY
S
Security @ Cisco Blogs
The Hacker News
The Hacker News
SecWiki News
SecWiki News
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Simon Willison's Weblog
Simon Willison's Weblog
C
Cisco Blogs
A
Arctic Wolf
S
Securelist
Hacker News - Newest:
Hacker News - Newest: "LLM"
AI
AI
N
News and Events Feed by Topic
L
LINUX DO - 热门话题
P
Privacy & Cybersecurity Law Blog
Google Online Security Blog
Google Online Security Blog
T
The Exploit Database - CXSecurity.com
The Last Watchdog
The Last Watchdog
S
Secure Thoughts
Webroot Blog
Webroot Blog
Scott Helme
Scott Helme
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
S
Schneier on Security
Latest news
Latest news
T
Threatpost
K
Kaspersky official blog
Know Your Adversary
Know Your Adversary
Schneier on Security
Schneier on Security
I
Intezer
PCI Perspectives
PCI Perspectives
S
Security Affairs
爱范儿
爱范儿
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

Hacker News

Introducing Claude Opus 4.7 Qwen Studio The Future of Everything is Lies, I Guess: Where Do We Go From Here? GitHub - SeanFDZ/macmind: Single-layer transformer in HyperTalk for the classic Macintosh Show HN: Agent-cache – Multi-tier LLM/tool/session caching for Valkey and Redis Bonsai 1-bit WebGPU - a Hugging Face Space by webml-community Moving a large-scale metrics pipeline from StatsD to OpenTelemetry / Prometheus GitHub - Nightmare-Eclipse/RedSun: The Red Sun vulnerability repository GitHub - SethPyle376/hiraeth: Local AWS emulator focused on fast integration testing, with SQS support, SQLite-backed state, and a debug-friendly web UI. GitHub - macOS26/Agent: Any AI, replaces Claude Code, Cursor, OpenClaw. Over 18 LLM providers (Claude, OpenAI, Gemini, Ollama, Zai, HF, Qwen) wired into a native Mac app that writes code, builds Xcode projects, bumps versions, manages git, automates Safari, use AppleScript, JS or Accessibility, extend Agent! w/ MCP Servers, run tasks from your iPhone via Messages. YouTube now lets you turn off Shorts I Made a Terminal Pager Burgers | マクドナルド公式 Commands — HackerNews CLI documentation ChatGPT for Excel PiCore - Raspberry Pi Port of Tiny Core Linux Live Nation illegally monopolized ticketing market, jury finds Google Broke Its Promise to Me. Now ICE Has My Data. Founding Engineer at Adaptional | Y Combinator CRISPR takes important step toward silencing Down syndrome’s extra chromosome GitHub - saffron-health/libretto: The AI toolkit for building reliable browser automations US v. Heppner (S.D.N.Y. 2026) no attorney-client privilege for AI chats [pdf] Retrofitting JIT Compilers into C Interpreters IPv6 – Google The Accursèd Alphabetical Clock Cybersecurity Looks Like Proof of Work Now Fragments: April 14 Cal.com Goes Closed Source: Why AI Security Is Forcing Our Decision | Cal.com - Scheduling Software for Online Bookings Laravel raised money and now injects ads directly into your agent When moving fast, talking is the first thing to break Too much Discussion of the XOR swap trick – Heather Cafe Introduction to Spherical Harmonics for Graphics Programmers The Grand Line Building a Z-Machine in the worst possible language High-Level Rust: Getting 80% of the Benefits with 20% of the Pain GitHub - duguyue100/midnight-captain: Inspired by Midnight Commander, tailored to my taste. How to build a `git diff` driver · Jamie Tanna | Software Engineer Center for Responsible, Decentralized Intelligence at Berkeley The Local Universe’s Expansion Rate Is Clearer Than Ever, but Still Doesn’t Add Up - A new synthesis of astronomical measurements confirms a persistent mismatch that could point to physics beyond current models The air throughout our homes is infused with microplastics. But there are things you can do to breathe less of them The disturbing white paper Red Hat is trying to erase from the internet – OSnews The Future of Everything is Lies, I Guess: Annoyances ‘Abhorrent’: the inside story of the Polymarket gamblers betting millions on war Productive procrastination — Max van IJsselmuiden maps, territory and LMs 447 Terabytes per Square Centimetre at Zero Retention Energy: Non-Volatile Memory at the Atomic Scale on Fluorographane Show HN: Pardonned.com – A searchable database of US Pardons 20 Years on AWS and Never Not My Job The Seasons are Wrong Artemis II crew splashes down near San Diego after historic moon mission We gave an AI a 3 year retail lease in SF and asked it to make a profit | Andon Labs How a dancer with ALS used brainwaves to perform live On filing the corners off my MacBooks Installing every* Firefox extension OpenClaw’s memory is unreliable, and you don’t know when it will break Steve Blank Nowhere Is Safe Chimpanzees in Uganda locked in vicious 'civil war', say researchers watgo - a WebAssembly Toolkit for Go linux/Documentation/process/coding-assistants.rst at master · torvalds/linux GitHub - callumlocke/json-formatter: Makes JSON easy to read. Founding Product Engineer at Bild AI | Y Combinator A compelling title that is cryptic enough to get you to take action on it GitHub - Keychron/Keychron-Keyboards-Hardware-Design: Industrial design files for Keychron keyboards and mice. 100+ models with CAD assets in STEP, DXF, DWG, and PDF. Source-available, with commercial use allowed for original compatible accessories within the license terms. [ANNOUNCE] WireGuardNT v0.11 and WireGuard for Windows v0.6 Released 1D-Chess Helium Is Hard to Replace Cooperative Vectors Introduction | Evolve Keeping a Postgres queue healthy — PlanetScale Our response to the Axios developer tool compromise Do Americans read print books, e-books or audiobooks more? The Zettelkasten Method in Obsidian: A Practical Setup Guide Artemis II Is Competency Porn and We Are Starving For It WeakC4 Flight Viz — Cockpit View A Mexican surveillance giant you’ve never heard of is now watching the U.S. border Surelock: Deadlock-Free Mutexes for Rust RISC-V 101 – what is it and what does it mean for Canonical? | Ubuntu The Problem That Built an Industry How Much Linear Memory Access Is Enough? | Solidean Investigating Split Locks on x86-64 Simplest hash functions Sybilproof reputation mechanisms (2005) [pdf] What is a property? How Complex is my Code? Static code analysis in Kotlin — tools overview Toffoli gates are all you need PGLite evangelism dcmake: a new CMake debugger UI Clojure on Fennel part one: Persistent Data Structures Fragments: April 2 Python Release Python install manager 26.1 The Life and Death of the Book Review - Liberties Introducing Database Traffic Control — PlanetScale Bitcoin miners are losing $19,000 on every BTC produced as difficulty drops 7.8% God sleeps in the minerals Building slogbox Apple Silicon and Virtual Machines: Beating the 2 VM Limit Who was “Not Even Wrong” first? Pokemon Evolution Vs Darwinian Evolution The APL Programming Language Source Code
Rust Memory Management: Ownership vs. Reference Counting
2026-04-25 · via Hacker News

Rust's signature achievement is memory safety without a garbage collector. It accomplishes this through a disciplined ownership system — but that system deliberately has an escape hatch: reference counting.

Every value in a Rust program has a single owner at any given time. When that owner goes out of scope, the value is dropped — memory freed, deterministically, at a known point in execution. No GC pause, no dangling pointer, no double-free. The compiler enforces all of this statically.

But some data genuinely needs to be shared: a node in a graph owned by multiple edges, a configuration object threaded through many subsystems, a callback holding a reference into surrounding state. Enter reference countingRc<T> and Arc<T> — which shift ownership logic from compile time into a small runtime counter.

These are not competing features. They are complementary tools with distinct trade-offs. This article unpacks both — semantics, performance, ergonomics, and the decisive question: which should you reach for?


The ownership model is Rust's core innovation. Every heap allocation has exactly one owner — the variable binding that "holds" it. Ownership can be moved to another binding, at which point the original is invalidated. It can never be silently copied (unless the type implements Copy).

Move Semantics

fn main() {
    let s1 = String::from("hello");
    let s2 = s1;  // ownership MOVED — s1 is now invalid

    // println!("{}", s1);  ← compile error: value borrowed after move
    println!("{}", s2);  // fine — s2 is the sole owner
} // s2 dropped here, memory freed automatically

The borrow checker enforces the ownership rules. When s1 is assigned to s2, the compiler understands that s1 can no longer be used — it has given up ownership. This eliminates use-after-free at zero runtime cost.

Borrowing — Shared (&T) and Mutable (&mut T)

Moving ownership everywhere would be cumbersome. Rust lets you borrow a value: take a temporary, scoped reference without transferring ownership.

fn calculate_length(s: &String) -> usize {
    s.len()
}  // s goes out of scope but does NOT drop the String

fn append_world(s: &mut String) {
    s.push_str(", world");
}

fn main() {
    let mut greeting = String::from("hello");

    let len = calculate_length(&greeting); // shared borrow
    append_world(&mut greeting);          // mutable borrow

    println!("'{}' has {} characters", greeting, len);
}

The borrow checker enforces two invariants simultaneously:

  • Any number of shared (&T) borrows may coexist — they are read-only and cannot alias a mutation.
  • Exactly one mutable (&mut T) borrow may exist at a time — and no shared borrows may co-exist with it.

This is aliasing XOR mutability — a fundamental rule that eliminates entire categories of bugs (iterator invalidation, data races) statically.

Lifetimes

References are augmented with lifetimes — annotations that prove a reference cannot outlive the data it points to. In most code the compiler infers them; in complex generic APIs you annotate explicitly.

// 'a says: the returned reference lives at least as long as both inputs
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() >= y.len() { x } else { y }
}

Key Properties

Ownership & Borrowing is zero-cost: all safety guarantees are verified at compile time and produce no runtime overhead — no counter increments, no heap allocations beyond the value itself, no extra indirection.


Ownership is a strict single-owner model. But some programs require shared ownership — multiple parts of a program that each need to keep a value alive. The classic example is a graph where multiple edges point to the same node.

Rc<T> (Reference Counted) wraps a value on the heap alongside a pair of counters: a strong count (active owners) and a weak count. Every clone of the Rc increments the strong count; every drop decrements it. When the strong count reaches zero, the inner value is dropped.

Basic Usage

use std::rc::Rc;

fn main() {
    let a = Rc::new(String::from("shared data"));
    let b = Rc::clone(&a);  // increments strong count — cheap pointer clone
    let c = Rc::clone(&a);

    println!("strong count = {}", Rc::strong_count(&a)); // 3

    drop(b);
    println!("after drop b = {}", Rc::strong_count(&a)); // 2

} // a and c drop here; count → 0 → String is freed

Interior Mutability with RefCell

Rc<T> gives shared ownership but immutable access. To mutate the inner value you pair it with RefCell<T>, which moves borrow checking from compile time to runtime:

use std::rc::Rc;
use std::cell::RefCell;

fn main() {
    let shared = Rc::new(RefCell::new(vec![1, 2, 3]));

    let clone1 = Rc::clone(&shared);
    let clone2 = Rc::clone(&shared);

    clone1.borrow_mut().push(4);  // runtime borrow check
    clone2.borrow_mut().push(5);

    println!("{:?}", shared.borrow()); // [1, 2, 3, 4, 5]
}

Thread-Safe Sharing: Arc<T>

Rc<T> is not Send or Sync — its counter is not atomic and cannot cross thread boundaries. For concurrent use, swap in Arc<T> (Atomically Reference Counted), which uses atomic CPU operations for the counter. For interior mutability across threads, pair it with Mutex<T> or RwLock<T>.

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0u32));

    let handles: Vec<_> = (0..8).map(|_| {
        let c = Arc::clone(&counter);
        thread::spawn(move || {
            *c.lock().unwrap() += 1;
        })
    }).collect();

    for h in handles { h.join().unwrap(); }
    println!("count = {}", *counter.lock().unwrap()); // 8
}

Watch Out — Reference Cycles

Rc<T> and Arc<T> cannot automatically detect reference cycles. If two Rc values hold each other, their strong counts never reach zero and you leak memory. Use Weak<T> for back-references (e.g., parent pointers in a tree) to break cycles.


Dimension Ownership & Borrowing Rc<T> / Arc<T>
Ownership model Single owner, strictly enforced Shared ownership via counted handles
Verification Compile time — zero runtime cost Runtime — counter ops on every clone/drop
Performance Zero overhead — no extra indirection Small overhead: heap alloc, counter, pointer deref
Thread safety Enforced by Send/Sync compile-time Rc: single-thread only; Arc: thread-safe
Mutation &mut T — exclusive, statically checked Requires RefCell/Mutex — runtime panics possible
Cycles N/A — single owner can't cycle with itself Reference cycles leak memory — use Weak<T>
API complexity Steeper learning curve (lifetimes) Simpler surface; complexity moves to runtime
Typical use case Default for almost all data in Rust Graphs, trees with shared nodes, shared config, callbacks
Drop timing Deterministic — at end of owner's scope Deterministic — when last handle drops (may be non-obvious)
Cloning cost Deep copy (or move — free) Pointer copy + counter increment — O(1)

Performance in Practice

The overhead of Rc<T> is three-fold: one extra heap allocation for the control block, one pointer indirection on every access, and two integer increments/decrements on clone and drop. For most programs this is negligible. For hot-path code with millions of operations per second — game engines, compilers, signal processors — preferring owned values matters.

Arc<T> adds further cost: atomic operations use CPU memory-ordering guarantees (SeqCst or Release/Acquire), which inhibit certain compiler and hardware reorderings. On contended multi-core workloads, this can become measurable.

Rule of Thumb

Reach for Rc/Arc when the alternative is fighting the borrow checker with complex lifetime annotations or unsafe code. The small runtime cost buys you ergonomic, safe shared ownership — a reasonable trade in most application code.


Prefer Ownership + Borrowing when…

  • Data has a clear single logical owner (most structs, collections, I/O resources).
  • You need deterministic, minimal-overhead destruction (RAII for files, sockets, locks).
  • You are writing library code where callers should control lifetimes.
  • Performance is critical and every allocation counts.

Prefer Rc<T> / Arc<T> when…

  • Multiple owners genuinely need to keep the same data alive (graph nodes, parse trees, event listeners).
  • The lifetime of data is determined dynamically at runtime, not statically.
  • You are bridging with external systems that expect reference semantics (Python extensions, GUI frameworks).
  • You want shared state across threads without copying large structures (Arc<Mutex<T>>).
// Classic use case: graph with shared nodes
use std::rc::{Rc, Weak};
use std::cell::RefCell;

struct Node {
    value: i32,
    children: Vec<Rc<RefCell<Node>>>>,
    parent: Option<Weak<RefCell<Node>>>>, // Weak breaks parent→child cycle
}

impl Node {
    fn new(value: i32) -> Rc<RefCell<Node>> {
        Rc::new(RefCell::new(Node {
            value,
            children: vec![],
            parent: None,
        }))
    }
}