标签: copy-on-write

什么是隐式共享?

我正在用C++构建一个游戏引擎库.不久前,我使用Qt构建了一个应用程序,并且对使用Implicit Sharing非常着迷.我想知道是否有人可以更详细地解释这种技术,或者可以提供一个简单的例子.

c++ qt copy-on-write

13
推荐指数
1
解决办法
5750
查看次数

在R中修改矩阵

我有什么方法可以避免修改副本的原位修改R

我试图将较小的矩阵复制到一个较大的矩阵切片,如下所示.

library(data.table)
y <- matrix(c(11,21,31,12,22,32),nrow=3,ncol=2)
address(y)
[1] "08429190"

y[2:3,] <- matrix(c(1,1,8,12),nrow=2)
address(y)
[1] "0E033D28"
Run Code Online (Sandbox Code Playgroud)

r matrix copy-on-write data.table

13
推荐指数
1
解决办法
904
查看次数

Python多处理写时复制在OSX和Ubuntu之间表现不同

我正在尝试在Python中的父进程和子进程之间共享对象.为了解决这个想法,我创建了一个简单的Python脚本:

from multiprocessing import Process
from os import getpid

import psutil

shared = list(range(20000000))

def shared_printer():
    mem = psutil.Process(getpid()).memory_info().rss / (1024 ** 2)
    print(getpid(), len(shared), '{}MB'.format(mem))

if __name__ == '__main__':
    p = Process(target=shared_printer)
    p.start()
    shared_printer()
    p.join()
Run Code Online (Sandbox Code Playgroud)

代码片段使用优秀的psutil库来打印RSS(驻留集大小).当我在OSX上用Python 2.7.15运行它时,我得到以下输出:

(33101, 20000000, '1MB')
(33100, 20000000, '626MB')
Run Code Online (Sandbox Code Playgroud)

当我在Ubuntu上运行完全相同的代码片段(Linux 4.15.0-1029-aws#30-Ubuntu SMP x86_64 GNU/Linux)时,我得到以下输出:

(4077, 20000000, '632MB')
(4078, 20000000, '629MB')
Run Code Online (Sandbox Code Playgroud)

请注意,子进程'RSS在OSX上是基本的0MB,与Linux中的父进程'RSS大小相同.我曾假设写入时复制行为在Linux中的工作方式相同,并允许子进程为大多数页面引用父进程的内存(可能除了存储对象头部的内存之外).

所以我猜测2系统中的写时复制行为存在一些差异.我的问题是:在Linux中我能做些什么来获得类似OSX的写时复制行为?

python linux copy-on-write shared-memory python-multiprocessing

13
推荐指数
1
解决办法
372
查看次数

Golang函数参数是否作为copy-on-write传递?

我有以下功能:

func checkFiles(path string, excludedPatterns []string) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

我想知道,因为excludedPatterns永远不会改变,我应该通过使var全局(而不是每次都将它传递给函数)来优化它,或者Golang是否已经通过将它们作为copy-on-write传递来处理它?

编辑:我想我可以将切片作为指针传递,但我仍然想知道写时复制行为(如果它存在)以及一般来说我是否应该担心通过值或指针传递.

parameter-passing copy-on-write go

12
推荐指数
1
解决办法
4830
查看次数

R:选择子集而不复制

有没有办法从对象(数据框,矩阵,向量)中选择一个子集而无需复制所选数据?

我使用相当大的数据集,但从不更改它们.然而,为方便起见,我选择要操作的数据子集.每次制作一个大的子集的副本是非常低效的内存,但是正常的索引和subset(以及因此xapply()的函数族)都创建了所选数据的副本.所以我正在寻找可以解决这个问题的功能或数据结构.

一些可能符合我需求的方法,并希望在一些R包中实现:

  • 写时复制机制,即仅在添加或重写现有元素时复制的数据结构;
  • 不可变数据结构,只需要为数据结构重新创建索引信息,而不是其内容(比如通过仅创建保存长度的小对象和指向同一个char数组的指针来从字符串中创建子字符串);
  • xapply() 不创建子集的类似物.

r subset immutability copy-on-write apply

10
推荐指数
1
解决办法
2144
查看次数

Ruby 2.2中的垃圾收集器引发了意想不到的CoW

当我分叉我的进程时,如何防止GC激发写时复制?我最近一直在分析垃圾收集器在Ruby中的行为,因为我在程序中遇到了一些内存问题(即使对于相当小的任务,我的60核0.5Tb机器上的内存耗尽).对我来说,这确实限制了ruby在多核服务器上运行程序的实用性.我想在这里介绍我的实验和结果.

垃圾收集器在分叉期间运行时会出现问题.我调查了三个案例来说明这个问题.

情况1:我们使用数组在内存中分配了大量对象(字符串不超过20个字节).使用随机数和字符串格式创建字符串.当进程分叉并强制GC在子进程中运行时,所有共享内存都是私有的,导致初始内存重复.

情况2:我们使用数组在内存中分配了很多对象(字符串),但是使用rand.to_s函数创建了字符串,因此我们删除了与前一种情况相比的数据格式.我们最终使用的内存较少,可能是因为垃圾较少.当进程分叉并强制GC在子进程中运行时,只有部分内存变为私有.我们有重复的初始内存,但程度较小.

情况3:与之前相比,我们分配的对象更少,但对象更大,因此分配的内存量与之前的情况相同.当进程分叉并且我们强制GC在子进程中运行时,所有内存保持共享,即没有内存重复.

在这里,我粘贴用于这些实验的Ruby代码.要在不同情况之间切换,只需更改memory_object函数中的"option"值即可.在Ubuntu 14.04计算机上使用Ruby 2.2.2,2.2.1,2.1.3,2.1.5和1.9.3测试了代码.

案例1的示例输出:

ruby version 2.2.2 
 proces   pid log                   priv_dirty   shared_dirty 
 Parent  3897 post alloc                   38            0 
 Parent  3897 4 fork                        0           37 
 Child   3937 4 initial                     0           37 
 Child   3937 8 empty GC                   35            5 
Run Code Online (Sandbox Code Playgroud)

完全相同的代码是用Python编写的,在所有情况下,CoW都可以正常工作.

案例1的示例输出:

python version 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] 
 proces   pid log                   priv_dirty shared_dirty 
 Parent  4308 post alloc                35             0 
 Parent  4308 4 fork                     0            35 
 Child   4309 4 initial                  0            35 
 Child   4309 10 …
Run Code Online (Sandbox Code Playgroud)

ruby garbage-collection fork copy-on-write shared-memory

10
推荐指数
1
解决办法
620
查看次数

写时复制会阻止数组上的数据重复吗?

我正在使用PHP编写Web API客户端,将CSV数据解析为关联数组,并且我希望在使用这些数组时保护我的用户免受数据复制.

我的用户永远不会写这些数组(理论上他们可以,但在实践中没有意义).

现在我的问题是......如果我的用户将这些数组作为方法的参数传递,那么PHP的写时复制机制是否会阻止数据复制,或者任何未明确接受对数组的引用的方法都会收到完整的副本阵列?

php arrays duplicates copy-on-write

9
推荐指数
1
解决办法
3929
查看次数

fork()中的copy-on-write如何处理多个fork?

根据维基百科(可能是错的)

发出fork()系统调用时,会创建与父进程对应的所有页面的副本,由OS进行子进程加载到单独的内存位置.但在某些情况下不需要这样做.考虑一个子进行"exec"系统调用(用于执行C程序中的任何可执行文件)或fork()之后很快退出的情况.当需要子进程来执行父进程的命令时,不需要复制父进程的页面,因为exec用要执行的命令替换调用它的进程的地址空间.

在这种情况下,使用称为写时复制(COW)的技术.使用此技术,当发生fork时,不会为子进程复制父进程的页面.相反,页面在子进程和父进程之间共享.每当进程(父进程或子进程)修改页面时,就会对执行修改的进程(父进程或子进程)单独创建该特定页面的单独副本.然后,此过程将使用新复制的页面,而不是将来所有引用中的共享页面.另一个进程(未修改共享页面的进程)继续使用页面的原始副本(现在不再共享).这种技术称为写时复制,因为当某个进程写入页面时会复制该页面.

似乎当任一进程尝试写入页面时.将分配新页面副本并将其分配给生成页面错误的进程.之后,原始页面被标记为可写.

我的问题是:如果在任何进程尝试写入共享页面之前多次调用fork,会发生什么?

linux memory fork copy-on-write

9
推荐指数
1
解决办法
5204
查看次数

STL中的写时复制支持

我刚刚阅读了一篇关于写时复制的维基百科文章(如果有任何支持它的文件系统很好奇),并对以下段落感到惊讶:

COW也在内核之外,库,应用程序和系统代码中使用.例如,C++标准库提供的字符串类是专门为允许写时复制实现而设计的:

std::string x("Hello");

std::string y = x;  // x and y use the same buffer

y += ", World!";    // now y uses a different buffer
                    // x still uses the same old buffer
Run Code Online (Sandbox Code Playgroud)

我不知道STL中是否支持copy-on-write.真的吗?它是否适用于其他STL类,例如std::vectorstd::array?哪些编译器支持该优化(特别是,我想知道G ++,英特尔C++编译器和Microsoft C++编译器)?

c++ compiler-construction stl copy-on-write

9
推荐指数
1
解决办法
5943
查看次数

使用shared_ptr复制写入

所以我有一个简单的cow_ptr.它看起来像这样:

template<class T, class Base=std::shared_ptr<T const>>
struct cow_ptr:private Base{
  using Base::operator*;
  using Base::operator->;
  using Base::operator bool;
  // etc

  cow_ptr(std::shared_ptr<T> ptr):Base(ptr){}

  // defaulted special member functions

  template<class F>
  decltype(auto) write(F&& f){
    if (!unique()) self_clone();
    Assert(unique());
    return std::forward<F>(f)(const_cast<T&>(**this));
  }
private:
  void self_clone(){
    if (!*this) return;
    *this = std::make_shared<T>(**this);
    Assert(unique());
  }
};
Run Code Online (Sandbox Code Playgroud)

这可以保证它拥有一个非常量T并确保它在unique何时出现.write([&](T&){}).

的折旧.unique()似乎表明这种设计是有缺陷的.

我猜测如果我们从线程A中的cow_ptr<int> ptrwith 开始1,将它传递给线程B,使其唯一,修改它2,传ptr回它并在线程中读取它A我们已经生成了竞争条件.

我该如何解决?我可以简单地添加内存屏障write吗?哪一个?或者问题更根本? …

c++ copy-on-write memory-barriers c++17

8
推荐指数
1
解决办法
334
查看次数