从子堆栈中删除Perl模块

从子堆栈中删除Perl模块,perl,memory,fork,Perl,Memory,Fork,我有一个守护进程,它加载DBI(DBD::mysql),然后派生子进程。我想防止DBI模块出现在分叉子进程的内存中 比如说: #!/usr/bin/perl use DBI; my $dbh = DBI->connect(db_info); my $pid = fork(); if($pid){ # The forked process here should not have DBI loaded } 谢谢你的帮助 除非你把货物放在叉子后面,否则你不可能轻易做到这一点。但要做到

我有一个守护进程,它加载DBI(DBD::mysql),然后派生子进程。我想防止DBI模块出现在分叉子进程的内存中

比如说:

#!/usr/bin/perl

use DBI;
my $dbh = DBI->connect(db_info);

my $pid = fork();
if($pid){

# The forked process here should not have DBI loaded

}

谢谢你的帮助

除非你把货物放在叉子后面,否则你不可能轻易做到这一点。但要做到这一点,您必须不使用
使用
。改为这样做:

my $pid = fork();
if ($pid) {
     # child
} else {
     require DBI;
     import DBI;
}

这将防止DBI模块在fork之后加载。
use
例程基本上执行require/import,但在BEGIN{}块中,这就是为什么您不必使用它的原因。

如果您运行的是现代Linux系统,那么fork就是COW(写时复制)。这意味着只有父级或子级修改了父级的页面,才会将其复制到子级的地址空间。因此,DBI模块不在分叉子进程的内存中


Perl5没有任何从内存卸载模块的方法。如果出于某种原因确实需要子代码与父代码具有不同的代码,那么最好将该代码作为自己的脚本从主代码中分离出来,然后在fork之后使用来运行子脚本。这将比普通的fork慢,因为它必须编译子代码,所以如果您经常fork,那么最好有两个通过套接字相互通信的脚本,并在fork之前有“child”脚本。

加载模块就是像脚本一样执行它。模块和Perl脚本之间绝对没有区别。要卸载模块,需要撤消运行该模块的效果。这不能机械地完成,也不可能手动完成

最简单的解决方案是让孩子
exec
something。它甚至可能是您正在运行的脚本

exec($^X, $0, '--child', @args)

通过将套接字绑定到孩子的fd 0(stdin)和fd 1(stdout),可以授予孩子访问套接字的权限。

现在知道您想用它做什么,因为没有一个好的方法卸载模块i Perl,这是一个很好的解决方案,可以将身份验证服务器与应用程序服务器分开编写。应用服务器询问身份验证服务器IP是否具有权限。这样,它们就处于完全不同的过程中。这可能还有安全方面的好处,因为应用程序代码无法访问身份验证数据库

由于任何给定的应用程序都可能会扩展到需要自己的SQL数据库的程度,因此此练习可能是徒劳的,但是您的调用是无效的


这是一堆额外的工作、维护和复杂性。只有当它给你带来真正的内存问题时才值得一试,而不仅仅是因为它让你感到不适。记住,RAM非常便宜。开发人员的时间非常昂贵。

问题是,主进程将根据需要生成子进程,而不是在脚本中的固定时间。您是否将
导入作为间接对象方法调用?!?恶心@Joel Berger,这不像是一个普通的方法调用(因为即使包没有
import
方法,也可以调用它),并且
import
在perlfunc中有文档记录。虽然我通常会在间接方法调用时发出“恶心!”的声音,但这是我唯一不发出的声音。@ikegami
import
是一个方法调用。将其写为import DBI
意味着它是一个函数。把它放在内置函数调用
requiredbi
的旁边,完全是误导。
import
有一个神奇的默认实现,它是在类
DBI
上调用的方法,不是内置函数,也不是当前命名空间中的函数。@Schwern,只有当您否认存在间接方法调用,并且如果您错误地认为有人暗示
import
是一个函数,那么您的回答才是相关的。将其视为导致方法调用的函数是完全正确的。不管你怎么说,这绝对不是一个普通的方法调用。它的行为实际上就像一个函数(
sub{my$method=$\u0]->can('import');goto&$method if$method;}
),把它看作一个函数是很好的,因为这样做没有问题。你能解释一下为什么要这样做吗?这是一个非常奇怪的请求。当然,我有一个服务器守护进程,它分叉子进程。chld进程不需要访问DBI,但主进程需要,因为它使用数据库加载可接受的对等主机IP列表。因此,在分出一个单独的进程通过套接字进行通信之前,主线程会验证它是一个可接受的IP进行通信。您是否有证据证明DBI导致内存问题,或者这只是一种预感?嗯,它并不是真的导致“问题”。只是在执行子进程的lsof时,它似乎被复制到内存中。由于有数百个子进程,它看起来是最好的解决方案(因为它占用的空间最大),虽然这可以解决所述的问题,但值得注意的是,除非子进程非常小,否则它将占用更多的时间和内存来执行一个新的Perl进程,而不是制作一个叉子。@Schwern,你在说什么?除非执行fork,否则不能执行
exec
。是的,它会占用更多的内存,但实际上,OP不想与父级共享任何内存。我指的是fork+exec与fork。由于这是一个网络守护进程,孩子需要访问套接字,或者更确切地说,访问主套接字的“已接受”客户端。这样做的全部目的是保持每个子进程的内存使用率较低,因此据我所知,这将增加使用率。是吗?@GoldenNewby,你不可能有一个新的口译员,而且不花任何内存就可以得到它。由您决定是否不使用更多内存比不在子系统中加载DBI更重要。最后,它实际上可能会占用更少的内存。这取决于有多少p