Rc依赖周期的最小示例是什么? [英] What is a minimal example of an Rc dependency cycle?

查看:86
本文介绍了Rc依赖周期的最小示例是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个会泄漏内存的Rust程序归因于带有引用计数的循环.根据Valgrind的说法,以下示例似乎会导致内存泄漏,但不会泄漏内存.有什么作用?

I'm trying to write a Rust program that leaks memory due to cycles with reference counts. The following example, which seems like it should cause a memory leak, does not leak memory according to Valgrind. What gives?

test.rs:

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

struct Foo {
    f: Rc<Bar>,
}

struct Bar {
    b: RefCell<Option<Rc<Foo>>>,
}

fn main() {
    let bar = Rc::new(Bar {
        b: RefCell::new(None),
    });
    let foo = Rc::new(Foo { f: bar.clone() });
    *bar.b.borrow_mut() = Some(foo.clone());
}

Valgrind输出:

Valgrind output:

$ rustc --version
rustc 1.4.0 (8ab8581f6 2015-10-27)
$ rustc -o test test.rs
$ valgrind test
==23331== Memcheck, a memory error detector
==23331== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==23331== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==23331== Command: test
==23331== 
==23331== 
==23331== HEAP SUMMARY:
==23331==     in use at exit: 0 bytes in 0 blocks
==23331==   total heap usage: 37 allocs, 37 frees, 9,078 bytes allocated
==23331== 
==23331== All heap blocks were freed -- no leaks are possible
==23331== 
==23331== For counts of detected and suppressed errors, rerun with: -v
==23331== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

推荐答案

对于您所使用的Rust版本,很可能您正在使用jemalloc,这在Valgrind上并不总是很好(请参阅链接的问题以获取更多信息).更多信息).对于现代版本的Rust,默认情况下使用系统分配器,并且您发布的代码会报告内存泄漏:

With the version of Rust you were using, it's most likely that you were using jemalloc, which doesn't always play well with Valgrind (see the linked questions for more information). With modern versions of Rust, the system allocator is used by default and the code you have posted does report memory leaks:

$ valgrind --leak-check=full ./test
==761== Memcheck, a memory error detector
==761== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==761== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==761== Command: ./test
==761==
==761==
==761== HEAP SUMMARY:
==761==     in use at exit: 56 bytes in 2 blocks
==761==   total heap usage: 13 allocs, 11 frees, 2,233 bytes allocated
==761==
==761== 56 (32 direct, 24 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==761==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==761==    by 0x10BDAB: alloc::alloc::alloc (in /tmp/test)
==761==    by 0x10BD17: alloc::alloc::exchange_malloc (in /tmp/test)
==761==    by 0x10C3F6: <alloc::rc::Rc<T>>::new (in /tmp/test)
==761==    by 0x10BF6F: test::main (in /tmp/test)
==761==    by 0x10DAF2: std::rt::lang_start::{{closure}} (in /tmp/test)
==761==    by 0x115CC2: {{closure}} (rt.rs:49)
==761==    by 0x115CC2: std::panicking::try::do_call (panicking.rs:297)
==761==    by 0x117BA9: __rust_maybe_catch_panic (lib.rs:87)
==761==    by 0x11677C: try<i32,closure> (panicking.rs:276)
==761==    by 0x11677C: catch_unwind<closure,i32> (panic.rs:388)
==761==    by 0x11677C: std::rt::lang_start_internal (rt.rs:48)
==761==    by 0x10DAD4: std::rt::lang_start (in /tmp/test)
==761==    by 0x10C19A: main (in /tmp/test)
==761==
==761== LEAK SUMMARY:
==761==    definitely lost: 32 bytes in 1 blocks
==761==    indirectly lost: 24 bytes in 1 blocks
==761==      possibly lost: 0 bytes in 0 blocks
==761==    still reachable: 0 bytes in 0 blocks
==761==         suppressed: 0 bytes in 0 blocks
==761==
==761== For counts of detected and suppressed errors, rerun with: -v
==761== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

我在Ubuntu上使用Valgrind 3.13.0和Rust 1.34.1,但是我不认为这会改变结果.

I am using Valgrind 3.13.0 with Rust 1.34.1 on Ubuntu, but I do not believe that would change the results.

还可以将伪值添加到结构中,以更轻松地在输出中找到它们.我使用的Box<[u8; 10240]>非常出色.

You can also add dummy values to your structs to more easily find them in the output. I used a Box<[u8; 10240]> which stands out pretty well.

对于 minimum ,我会为链接列表建模:

As for minimal, I'd model a linked list:

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

struct Node {
    next: RefCell<Option<Rc<Node>>>,
}

fn main() {
    let foo1 = Rc::new(Node {
        next: RefCell::new(None),
    });
    let foo2 = Rc::new(Node {
        next: RefCell::new(Some(foo1.clone())),
    });
    *foo1.next.borrow_mut() = Some(foo2.clone());
}

此程序还报告泄漏.

另请参阅:

  • Why does Valgrind not detect a memory leak in a Rust program using nightly 1.29.0?
  • Valgrind shows no allocations

这篇关于Rc依赖周期的最小示例是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆