- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
是否可以避免代表的 GC?
我正在构建一个任务系统。我有带有本地任务队列的 N 线程。任务队列基本上只是一个 Array!Fiber 任务
。因为不鼓励将纤程发送到不同的线程,所以我将关闭/委托(delegate)发送到线程,从该委托(delegate)创建纤程并将其放入数组 tasks
。
现在我发送的委托(delegate)是捕获变量的委托(delegate)。
//Some Pseudo code
auto f = //some function;
auto cell = Cell(...);
auto del = () {
let res = f();
cell.write(res);
}
send(del);
}
现在单元被堆分配并与原子计数器同步。然后我可以检查来自 cell
的原子计数器是否已达到 0
,如果达到了,我可以安全地从中读取。
问题在于捕获变量的委托(delegate)在 GC 上分配变量。现在我只分配一个指针,这可能不是一个大问题,但我仍然想避免 GC。
我该怎么做?
最佳答案
您可能已经知道这一切,但这是一个常见问题解答,所以我将写一些细节。
首先,让我们了解什么是委托(delegate)。就像切片只是一个与长度配对的 C 数据指针一样,委托(delegate)只是一个与函数指针配对的 C 数据指针。这些被一起传递给期望它们的函数,就好像它被定义了一样
struct d_delegate {
void* ptr; // yes, it is actually typed void*!
T* funcptr; // this is actually a function pointer
};
(请注意,当您尝试在类方法中使用嵌套委托(delegate)时,其中只有一个数据 ptr 是编译器错误背后的原因!)
那个void*
是指向数据的,就像切片一样,它可以来自不同的地方:
Object obj = new Object();
string delegate() dg = &obj.toString;
此时,dg.ptr
指向obj
,恰好是一个垃圾回收的类对象,不过只是因为我new
在上面编辑。
struct MyStruct {
string doSomething() { return "hi"; }
}
MyStruct obj;
string delegate() dg = &obj.doSomething;
在这种情况下,obj
由于我在上面的分配方式而存在于堆栈中,因此 dg.ptr
也指向该临时对象。
无论某物是否是委托(delegate),都没有说明用于它的内存分配方案 - 这可以说是危险的,因为传递给您的委托(delegate)可能指向一个临时对象,该对象将在您完成之前消失! (这是顺便使用 GC 的主要原因,以帮助防止此类 use-after-free 错误。)
那么,如果委托(delegate)可以来自任何对象,为什么它们被认为是 GC 这么多呢?好吧,当编译器认为委托(delegate)的生命周期比外部函数长时,自动生成的闭包可以将局部变量复制到 GC 段。
void some_function(void delegate() dg);
void foo() {
int a;
void nested() {
a++;
}
some_function(&nested);
}
在这里,编译器会将变量 a
复制到 GC 段,因为它假定 some_function
将保留它的副本并希望防止 use-after-free 错误(调试起来很痛苦,因为它经常导致内存损坏!)以及内存泄漏。
但是,如果您向编译器保证您将通过在委托(delegate)定义中使用 scope
关键字自己正确地完成它,它将信任您并将本地人留在他们所在的位置:
void some_function(scope void delegate() dg);
保持其余部分不变,它将不再分配副本。在函数定义方面这样做是最好的,因为作为函数作者,您可以确保您实际上不会保留副本。
不过,在使用方面,您也可以将其标记为范围:
void foo() {
int a;
void nested() {
a++;
}
// this shouldn't allocate either
scope void delegate() dg = &nested;
some_function(&dg);
}
因此,GC 自动分配内存的唯一时间是当局部变量被嵌套函数使用时 没有 scope
关键字。
注意 () => 不管什么
和 () { return foo; }
语法只是命名嵌套函数的简写,其地址被自动获取,因此它们的工作方式与上述相同。 dg = {a++;};
与上面的 dg = &nested;
相同。
因此,对您来说,关键的收获是,如果您想手动分配一个委托(delegate),您只需要手动分配一个对象并从其方法之一创建一个委托(delegate),而不是自动捕获变量!但是,您需要跟踪生命周期并正确释放它。这是棘手的部分。
所以对于你的例子:
auto del = () {
let res = f();
cell.write(res);
};
你可以把它翻译成:
struct Helper {
T res;
void del() {
cell.write(res);
}
}
Helper* helper = malloc(Helper.sizeof);
helper.res = res; // copy the local explicitly
send(&helper.del);
然后,在接收端,完成后不要忘记 free(dg.ptr);
以免泄漏。
或者,更好的是,如果您可以将 send
更改为仅实际获取 Helper
对象,则根本不需要分配它,只需传递它即可按值(value)。
我还想到,您可以在该指针中打包一些其他数据以就地传递其他数据,但这将是 abi hacking 并且可能是未定义的行为。如果你想玩,试试吧:)
关于d - 是否可以避免代表的 GC?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37841207/
我们已经有一个使用 AnyEvent 的库。它在内部使用 AnyEvent,并最终返回一个值(同步 - 不使用回调)。有什么方法可以将这个库与 Mojolicious 一起使用吗? 它的作用如下: #
我想从 XSD 文件生成带有 JAXB 的 Java 类。 问题是,我总是得到一些像这样的类(删除了命名空间): public static class Action { @X
我有一个关于 html 输入标签或 primefaces p:input 的问题。为什么光标总是自动跳转到输入字段。我的页面高度很高,因此您需要向下滚动。输入字段位于页面末尾,光标自动跳转(加载)到页
我今天在考虑面向对象设计,我想知道是否应该避免 if 语句。我的想法是,在任何需要 if 语句的情况下,您都可以简单地创建两个实现相同方法的对象。这两个方法实现只是原始 if 语句的两个可能的分支。
String graphNameUsed = graphName.getName(); if (graphType.equals("All") || graphType.equals(
我有一张友谊 table CREATE TABLE IF NOT EXISTS `friendList` ( `id` int(10) NOT NULL, `id_friend` int(10
上下文 Debian 64。Core 2 二人组。 摆弄循环。我使用了同一循环的不同变体,但我希望尽可能避免条件分支。 但是,即使我认为它也很难被击败。 我考虑过 SSE 或位移位,但它仍然需要跳转(
我最近在 Java 中创建了一个方法来获取字符串的排列,但是当字符串太长时它会抛出这个错误:java.lang.OutOfMemoryError: Java heap space我确信该方法是有效的,
我正在使用 (C++) 库,其中需要使用流初始化对象。库提供的示例代码使用此代码: // Declare the input stream HfstInputStream *in = NULL; tr
我有一个 SQL 查询,我在 WHERE 子句中使用子查询。然后我需要再次使用相同的子查询将其与不同的列进行比较。 我假设没有办法在子查询之外访问“emp_education_list li”? 我猜
我了解到在 GUI 线程上不允许进行网络操作。对我来说还可以。但是为什么在 Dialog 按钮点击回调上使用这段代码仍然会产生 NetworkOnMainThreadException ? new T
有没有办法避免在函数重定向中使用 if 和硬编码字符串,想法是接收一个字符串并调用适当的函数,可能使用模板/元编程.. #include #include void account() {
我正在尝试避免客户端出现 TIME_WAIT。我连接然后设置 O_NONBLOCK 和 SO_REUSEADDR。我调用 read 直到它返回 0。当 read 返回 0 时,errno 也为 0。我
我正在开发 C++ Qt 应用程序。为了在应用程序或其连接的设备出现故障时帮助用户,程序导出所有内部设置并将它们存储在一个普通文件(目前为 csv)中。然后将此文件发送到公司(例如通过邮件)。 为避免
我有一组具有公共(public)父类(super class)的 POJO。这些存储在 superclass 类型的二维数组中。现在,我想从数组中获取一个对象并使用子类 的方法。这意味着我必须将它们转
在我的代码中,当 List 为 null 时,我通常使用这种方法来避免 for 语句中的 NullPointerException: if (myList != null && myList.size
我正在尝试避免客户端出现 TIME_WAIT。我连接然后设置 O_NONBLOCK 和 SO_REUSEADDR。我调用 read 直到它返回 0。当 read 返回 0 时,errno 也为 0。我
在不支持异常的语言和/或库中,许多/几乎所有函数都会返回一个值,指示其操作成功或失败 - 最著名的例子可能是 UN*X 系统调用,例如 open( ) 或 chdir(),或一些 libc 函数。 无
我尝试按值提取行。 col1 df$col1[col1 == "A"] [1] "A" NA 当然我只想要“A”。如何避免 R 选择 NA 值?顺便说一句,我认为这种行为非常危险,因为很多人都会陷入
我想将两个向量合并到一个数据集中,并将其与函数 mutate 集成为 5 个新列到现有数据集中。这是我的示例代码: vector1% rowwise()%>% mutate(vector2|>
我是一名优秀的程序员,十分优秀!