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

推荐订阅源

A
Arctic Wolf
博客园 - 聂微东
F
Fortinet All Blogs
云风的 BLOG
云风的 BLOG
小众软件
小众软件
V
Visual Studio Blog
博客园 - 三生石上(FineUI控件)
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Cloudflare Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The GitHub Blog
The GitHub Blog
Y
Y Combinator Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园_首页
L
LangChain Blog
A
About on SuperTechFans
阮一峰的网络日志
阮一峰的网络日志
I
Intezer
T
The Blog of Author Tim Ferriss
Security Latest
Security Latest
C
CXSECURITY Database RSS Feed - CXSecurity.com
Know Your Adversary
Know Your Adversary
Simon Willison's Weblog
Simon Willison's Weblog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
P
Palo Alto Networks Blog
Scott Helme
Scott Helme
S
Secure Thoughts
Spread Privacy
Spread Privacy
T
Threat Research - Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
P
Privacy & Cybersecurity Law Blog
O
OpenAI News
H
Heimdal Security Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Help Net Security
Help Net Security
C
Cyber Attacks, Cyber Crime and Cyber Security
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
G
Google Developers Blog
博客园 - Franky
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
K
Kaspersky official blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
Tor Project blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Tenable Blog
Google Online Security Blog
Google Online Security Blog
PCI Perspectives
PCI Perspectives

Modular Blog

Qualcomm to Acquire Modular Modular 26.4: SOTA MoE Serving, Model Bringup via Agent Skills, Mojo 1.0 Beta 2 and More ModCon 2026: Modular’s Developer Conference Day Zero: MiniMax M3 Open Weights on Modular Cloud Modverse #55: Mojo 1.0 Beta, Community Mojo Libraries, and Real-Time Patient Conversations Powered by MAX What about OpenCL and CUDA C++ alternatives? (Democratizing AI Compute, Part 5) Why LLM Inference Needs a New Kind of Router - Part 3 Three trends from MLSys 2026 Why LLM Inference Needs a New Kind of Router - Part 2 How I built a pure Mojo app (and 10 libraries) with AI agents Hippocratic AI partners with Modular to power flexible, high-quality inference for real-time patient conversations Translating to Mojo via AI Agents Inkwell: Why Your Inference Platform Matters As Much As Your Model Why LLM Inference Needs a New Kind of Router - Part 1 Modular 26.3: Mojo 1.0 Beta, MAX Video Gen, and more Modverse #54: AMD AI DevDay, New Modular Offices, and a Community That Keeps Shipping How Frontier Coding Agents Built a Video Diffusion Pipeline on MAX TileTensor Part 1 - Safer, More Efficient GPU Kernels Modular Opens Edinburgh & San Francisco Offices Structured Mojo Kernels Part 4 - Portability and the Road Ahead Day Zero Launch: Fastest Performance for Gemma 4 on NVIDIA and AMD Modverse #54: From GTC to Edinburgh, a Community Building Momentum Software Pipelining for GPU Kernels: Part 1 - The Pipeline Problem Structured Mojo Kernels Part 3 - Composition in Practice Modular 26.2: State-of-the-Art Image Generation and Upgraded AI Coding with Mojo Modular at NVIDIA GTC 2026: MAX on Blackwell, Mojo Kernel Porting, and DeepSeek V3 on B200 Structured Mojo Kernels Part 2 - The Three Pillars Modverse #53: Community Builds, Research Milestones, and a Growing Ecosystem Structured Mojo Kernels Part 1 - Peak Performance, Half the Code The Claude C Compiler: What It Reveals About the Future of Software BentoML Joins Modular The Five Eras of KVCache Modular 26.1: A Big Step Towards More Programmable and Portable AI Infrastructure How to Beat Unsloth's CUDA Kernel Using Mojo—With Zero GPU Experience 🔥 Modular 2025 Year in Review The path to Mojo 1.0 Modverse #52: Advancing AI Together — Community Projects & Platform Milestones Modular 25.7: Faster Inference, Safer GPU Programming, and a More Unified Developer Experience "TTS 1 Max" (powered by Modular Platform) Ranked #1 Speech Model on Artificial Analysis PyTorch and LLVM in 2025 — Keeping up With AI Innovation Achieving State-of-the-Art Performance on AMD MI355 — in Just 14 Days Modular Raises $250M to scale AI's Unified Compute Layer Modular 25.6: Unifying the latest GPUs from NVIDIA, AMD, and Apple Matrix Multiplication on Blackwell: Part 4 - Breaking SOTA Modverse #51: Modular x Inworld x Oracle, Modular Meetup Recap and Community Projects Matrix Multiplication on Blackwell: Part 3 - The Optimizations Behind 85% of SOTA Performance Matrix Multiplication on Blackwell: Part 2 - Using Hardware Features to Optimize Matmul Matrix Multiplication on Blackwell: Part 1 - Introduction Modverse #50: Modular Platform 25.5, Community Meetups, and Mojo's Debut in the Stack Overflow Developer Survey Modular Platform 25.5: Introducing Large Scale Batch Inference SF Compute and Modular Partner to Revolutionize AI Inference Economics AI Agents for AWS Marketplace Modverse #49: Modular Platform 25.4, Modular 🤝 AMD, and Modular Hack Weekend Inside Modular Hack Weekend: Top Projects and Community Highlights How is Modular Democratizing AI Compute? (Democratizing AI Compute, Part 11) Modular 25.4: One Container, AMD and NVIDIA GPUs, No Lock-In Introducing Mammoth: Enterprise-Scale GenAI Deployments Made Simple Modular + AMD: Unleashing AI performance on AMD GPUs Modverse #48: Modular Platform 25.3, MAX AI Kernels, and the Modular GPU Kernel Hackathon Exploring Metaprogramming in Mojo Modular GPU Kernel Hackathon Highlights: Innovation, Community, & Mojo🔥 Modular’s bet to break out of the Matrix (Democratizing AI Compute, Part 10) Modular Platform 25.3: 450K+ Lines of Open Source Code and pip Packaging A New, Simpler License for MAX and Mojo Why do HW companies struggle to build AI software? (Democratizing AI Compute, Part 9) Modverse #47: MAX 25.2 and an evening of GPU programming at Modular HQ What about the MLIR compiler infrastructure? (Democratizing AI Compute, Part 8) What about Triton and Python eDSLs? (Democratizing AI Compute, Part 7) MAX 25.2: Unleash the power of your H200's–without CUDA! What about TVM, XLA, and AI compilers? (Democratizing AI Compute, Part 6) Modverse #46: MAX 25.1, MAX Builds, and Democratizing AI Compute CUDA is the incumbent, but is it any good? (Democratizing AI Compute, Part 4) MAX 25.1 - Introducing MAX Builds How did CUDA succeed? (Democratizing AI Compute, Part 3) Paged Attention & Prefix Caching Now Available in MAX Serve What exactly is “CUDA”? (Democratizing AI Compute, Part 2) Modular DeepSeek's Impact on AI (Democratizing AI Compute, Part 1) Modular Hands-on with Mojo 24.6 Evaluating Llama Guard with MAX 24.6 and Hugging Face Modular Introducing MAX 24.6: A GPU Native Generative AI Platform MAX GPU: State of the Art Throughput on a New GenAI platform Understanding SIMD: Infinite Complexity of Trivial Problems Community Spotlight: Writing Mojo with Cursor Hands-on with Mojo 24.5 MAX 24.5 - With SOTA CPU Performance for Llama 3.1 Announcing stack-pr: an open source tool for managing stacked PRs on GitHub Debugging in Mojo🔥 Write hardware-agnostic custom ops for PyTorch | Modular Take control of your AI Develop locally, deploy globally A brief guide to the Mojo n-body example What's new in MAX 24.4? MAX on macOS, fast local Llama3, native quantization and GGUF support What’s new in Mojo 24.4? Improved collections, new traits, os module features and core language enhancements MAX 24.4 - Introducing quantization APIs and MAX on macOS What ownership is really about: a mental model approach Fast⚡k-means clustering in Mojo🔥: a guide to porting Python to Mojo🔥 for accelerated k-means clustering
Deep dive into ownership in Mojo
No items found. · 2024-06-04 · via Modular Blog

This post blog is the second part of the series of ownership in Mojo. Please make sure to check out the first part, What Ownership is Really About: A Mental Model Approach, as we will build on concepts developed there. This post serves as accompanying material for the deep dive on ownership by our CEO, Chris Lattner. Be sure to watch the video as well, which covers how ownership is implemented in Mojo's compiler, providing further insights and technical details.

Understanding how ownership works in Mojo is essential to leveraging its memory management capabilities effectively. Mojo ensures memory safety similar to Rust and efficiency of C/C++ by enforcing strict ownership rules. In this part, we will explore how this is achieved through different kinds of values, ownership modifiers, and lifecycle management. 

Value kinds in Mojo

When Mojo compiler parses the code along with the type checker it outputs three kinds of values, each with distinct ownership and reference behavior: 

  • RValue (Owned Value): Represents a unique ownership, i.e., a unique reference or a unique typed pointer with a lifetime. 
  • LValue (Mutable Reference): Represents a mutable reference, allowing read and write access to the original value. 
  • BValue (Immutable Reference): Represents an immutable reference, allowing read-only access to the original value.

Intuitively, these values can be defined using the ownership model we built in the previous section as follows (Mojo-pseudocode):

Pseudocode

alias RValue = UniqueRef[T, Lifetime, Ownership = Unique] alias BValue = ImmutableRef[T, Lifetime, Ownership = Immutable] alias LValue = MutableRef[T, Lifetime, Ownership = Mutable]

These values propagate through the expression trees as the result of the Mojo parse. This is crucial for ensuring that the correct ownership and reference semantics are maintained throughout the program. 

Next, we will see how ownership can be modified in function arguments.

Ownership Modifiers in Function Arguments

Mojo’s argument convention in functions are as follows:

  • borrowed: The function receives an immutable reference (similar to ImmutableRef discussed previously). This means the function can read the original value (it is not a copy), but it cannot mutate (modify) it. Note that this is default in fn foo(x: T) i.e. fn foo(borrowed x: T)
  • inout: The function receives a mutable reference (similar to MutableRef). This means the function can read and mutate the original value (it is not a copy). 
  • owned: This means the function has an exclusive unique reference  (similar to UniqueRef) which can uniquely identify the underlying value. Often, this also implies that the caller should transfer ownership to this function, but that's not always what happens and this might instead be a copy. More on this later.

The first rule to note is:

Rule 1: owned arguments take RValue on the caller side but are LValue on the callee side.

When a function argument is declared as owned, it takes an RValue on the caller side but becomes an LValue on the callee side. This ensures that the function has exclusive access to the value, preventing other references from accessing or modifying it simultaneously. (The following is valid Mojo code):

Mojo

# a function that takes ownership of String fn take_ownership(owned y: String):    y = String("Bye!")  # y is an LValue here    print(y) fn main():    var x = String("hello, world!")    take_ownership(x^)  # x^ is passed as RValue    # print(x)  # This would cause a compile-time error as x's ownership has been transferred

In above, String("hello, world!") uses the constructor __init__ to create the RValue where var owns it and is named x. Then in take_ownership(x^), the x^ is passed as an RValue (caller side) whereas it is received as an LValue in the callee side which is x = String(“Bye!”). The output of the program is Bye! as expected.

For the purpose of completeness, we should mention that Mojo’s dataflow analysis determines where the last use of a variable has occurred and it injects its destructor __del__ eagerly. This is known as As Soon As Possible (ASAP) destructor. However, when transfer operator ^ is used, Mojo disables the call to String.__del__ and is correctly delegated to happen after take_ownership is done printing the new assigned value. For more, please check out the death of a value. 

Relations of the value kinds and ownership modifiers

This table depicts how Value kinds behave with function ownership modifiers.

__wf_reserved_inherit

Establish ownership behavior through __copyinit__ and __moveinit__

To implement custom behavior for copying and moving values, Mojo provides the __copyinit__ and __moveinit__ dunder methods, respectively. These methods allow you to define how values are copied or moved, ensuring that ownership is correctly transferred without unintended side effects. For more details, please check out the Mojo manual.

A type in Mojo can be:

Movable

Values that can be moved through __moveinit__, transferring ownership without copying the underlying data through the transfer operator ^. The transfer operator ^ is used to convert a BValue or LValue into an RValue. This is essential for transferring ownership while maintaining the original value’s integrity.

The following code simply prints when __moveinit__ is called:

Mojo

struct MovableOnly:    fn __init__(inout self): ...    fn __moveinit__(inout self, owned existing: Self):        print("Move is called") fn main():    var a = MovableOnly()    # var b = a # compiler error: 'Movable' is not copyable because it has no '__copyinit__'    var b = a^

In the above example, var b = a fails to compile because that assignment used the __copyinit__ which there is none here. Executing the code, outputs Move is called.

Copyable

Values that can be copied through __copyinit__. The following code simply prints when __copyinit__ is called:

Mojo

from benchmark import keep struct CopyableOnly:   fn __init__(inout self): ...   fn __copyinit__(inout self, existing: Self):       print("Copy is called") fn main():   var a = CopyableOnly()   var b = a   keep(a) # need to `keep` it otherwise, Mojo compiler sees it's unused and optimizes it away

The above var b = a calls the __copyinit__ and running the code confirms Copy is called. Note that we need to use keep(a) to keep the Mojo compiler away from optimizing it away as it was unused.

An important note is that the transfer operator ^ is still usable here and its behavior is delegated to __copyinit__. We can verify it as follows:

Mojo

fn main():    var a = CopyableOnly()    var b = a    var c = a^    keep(c)

which outputs:

Output

Copy is called Copy is called

This might be surprising at first! In order for transfer operator to actually move, we need to implement __moveinit__.

Copyable and Movable

Values can implement both __copyinit__ and __moveinit__. The following prints when __copyinit__ or __moveinit__ is called.

Mojo

from benchmark import keep struct CopyableMovable:    fn __init__(inout self): ...    fn __copyinit__(inout self, existing: Self):        print("Copy is called")    fn __moveinit__(inout self, owned existing: Self):        print("Move is called") fn main():    var a = CopyableMovable()    var b = a    var c = a^    keep(c)

which outputs:

Output

Copy is called Move is called

Given the above examples, we can deduce the following:

Rule 2: owned argument owns the type if the transfer operator ^ is used, otherwise it copies if the type is Copyable.

The Mojo compiler takes any opportunity to optimize memory management. In the above example, even without specifying var c = a^

Mojo

fn main():    var a = CopyableMovable()    var b = a    var c = a    keep(c)

The Mojo compiler sees that var c = a is the last use of a so it optimizes move over copy.

Output

Copy is called Move is called

Therefore, we can deduce the last rule:

Rule 3: Copy to move optimization if the type is Copyable and Movable on last use.

This is particularly beneficial for large or complex data structures, reducing the overhead associated with copying and enhancing performance. For example, in the following, avoiding extra copy is an important optimization that the Mojo compiler can do easily for us.

Mojo

struct Str:    var ptr: DTypePointer[DType.uint8]    var sz: Int    fn __init__(inout self):        self.ptr = DTypePointer[DType.uint8]()        self.sz = 0    fn __init__(inout self, str: StringLiteral):        self.sz = len(str)        self.ptr = DTypePointer[DType.uint8].alloc(self.sz)        memcpy(self.ptr, str.as_uint8_ptr(), self.sz)    fn __copyinit__(inout self, existing: Self):        # deep copy        self.sz = existing.sz        self.ptr = DTypePointer[DType.uint8].alloc(self.sz)        for i in range(self.sz):            self.ptr.store(i, existing.ptr.load(i))        print("Copy is called")    fn __moveinit__(inout self, owned existing: Self):        # shallow ptr copy        self.ptr = existing.ptr        self.sz = existing.sz        print("Move is called")    fn __del__(owned self):        self.ptr.free() fn main():    var s = Str("hello")    var t = s    var u = s    keep(u)

which the expected output is:

Output

Copy is called Move is called

Immovable

Values that cannot be copied or moved, ensuring that they remain in a fixed memory location. An example of such special immovable types is Atomic which cannot be copied or moved. Such behavior is critical to ensure correctness in multithreaded environments.

Conclusion

In the second part of the ownership series in Mojo, we built on the mental model developed in the first part and provided practical examples to illustrate how ownership works in Mojo. We covered the different kinds of values (BValue, LValue, and RValue) and how they propagate through expressions. We also explained the function argument conventions (borrowed, inout, owned) and demonstrated how these conventions help manage memory safely and efficiently. We concluded with three fundamental rules: 

  • Rule 1: Owned arguments take RValue on the caller side but are LValue on the callee side.
  • Rule 2: Owned arguments own the type if the transfer operator ^ is used; otherwise, they copy the type if it is Copyable. 
  • Rule 3: Copy operations are optimized to move operations if the type is Copyable and Movable and isn’t used anymore, reducing unnecessary overhead. 

Lastly, we emphasized that the main goals of ownership in Mojo are:

  • Memory Safety: Enforcing exclusive ownership and proper lifetimes to prevent memory errors such as use-after-free and double-free. 
  • Performance Optimization: Converting unnecessary copy operations into move operations to reduce overhead and enhance performance. 
  • Ease of Use: Automating memory management through ownership rules and the transfer operator, simplifying development. 
  • Compile-Time Guarantees: Providing strong compile-time guarantees through type-checking and dataflow lifetime analysis, catching errors early in the development process. 

By integrating these principles, Mojo offers a powerful and intuitive framework for memory management, enabling developers to write efficient, safe, and high-performance code. For a deeper understanding of the technical details and implementation of ownership in Mojo, make sure to watch the accompanying video by our CEO, Chris Lattner.

Additional resources:

Report feedback, including issues on our Mojo and MAX GitHub tracker.

Until next time!🔥