文件描述符存储在进程内存中的哪里?

时间:2017-05-30 06:37:55

标签: c linux memory-management file-descriptor

当从执行点调用函数A时,在内部它是指向函数A的地址的JMP语句。因此当前执行点被保存到堆栈中,PC加载被调用函数的地址A并继续。

要在函数调用之后返回执行点,功能块应该具有相同的推送并弹出到堆栈上。通常在退出函数的C中,定义的堆栈变量被销毁(我认为这意味着从堆栈中弹出),但我决定在我的函数中定义一个文件描述符变量。代码如下:

void main() {
    printf("In the beginning there was main()\n");
    func_call();
    printf("func_call complete\n");
    while(1);
}

void func_call() {
    int fp;
    //Opening a file to get handle to it.
    fp = open("stack_flush.c", O_RDONLY);
    if (fp < 0 ) {
        perror("fp could not open stack_flush.c");
        return;
    }
}

在运行此程序并检查lsof时,我可以看到fd在退出函数func_call()时仍处于打开状态。

stack_flu 3791 vvdnlt260    0u   CHR  136,1      0t0        4 /dev/pts/1
stack_flu 3791 vvdnlt260    1u   CHR  136,1      0t0        4 /dev/pts/1
stack_flu 3791 vvdnlt260    2u   CHR  136,1      0t0        4 /dev/pts/1
stack_flu 3791 vvdnlt260    3r   REG    8,3      526 24660187 /home/vvdnlt260/Nishanth/test_space/stack_flush.c

我检查了wikipedia条目中的文件描述符,我发现了这个:

  

为了执行输入或输出,进程通过系统调用将文件描述符传递给内核,内核将代表进程访问文件。该进程无法直接访问文件或inode表。

从上面的陈述中可以明显看出,文件描述符整数值存储在进程内存中,但是虽然它是在函数中定义的,但是文件描述符并不是函数本地的,因为它在函数退出时没有被删除。

所以我的问题是2折:

1)如果文件描述符是func_call()堆栈的一部分,那么代码如何返回到它的预函数调用执行点,尽管它还没有被弹出?同样在这种情况下,为什么在函数调用存在后它仍然存在?

2)如果不是func_call()堆栈的一部分,文件描述符在哪里驻留在进程内存中?

3 个答案:

答案 0 :(得分:2)

变量int fd;仅在函数func_call()中可见,并且在此函数完成执行后,它将弹出堆栈,并且可能在输入新函数时覆盖内存。您销毁指向该文件的某些int值这一事实并不意味着您关闭了所述文件。如果你做了类似的事情怎么办?

int global_fd;
void foo() {
    int local_fd = open("bar.txt", O_RDONLY);
    global_fd = local_fd;
}

并致电foo()?您是否希望在global_fd退出后不再使用foo

在这种情况下,将文件描述符视为一个指针是有帮助的,您要求内核为您提供该文件,它会为您提供一个值,您可以将其用作此特定文件的标记,令牌是你用来让内核知道像readlseek这样的函数应该在哪个文件上运行的东西。当令牌传递或销毁时,文件保持打开状态,因为销毁指针不会释放分配的内存。

答案 1 :(得分:1)

当您打开文件时,内核中存储了文件描述符的表。因此,当您打开文件时,您在该表中创建了一个条目。如果您不关闭文件(使用其描述符),则永远不会删除该条目(它并不意味着您无法再次打开该文件)。

  

如果文件描述符是func_call()堆栈的一部分,那么代码如何返回到它的预函数调用执行点,尽管它还没有被弹出?同样在这种情况下,为什么在函数调用存在后它仍然存在?

据我所知,每个进程只有一个堆栈,而不是每个函数。因此fp变量存储在进程的堆栈中,并在函数结束时从那里删除。

答案 2 :(得分:0)

文件描述符很特别。如你所知,他们只是整理。但它们“包含”有关正在读取的文件的大量信息(磁盘上文件的位置,读/写指针的位置内的位置等),那么存储的信息在哪里?答案是它存储在OS内核中的某个地方。它存储在OS内核中,因为它是内核管理文件I / O的工作。当我们说引用打开文件的int是“文件描述符”时,我们的意思是int指的是存储在其他地方的信息,有点像指针。那个词“描述符”很重要。有时用于这种情况的另一个词是“处理”。

如您所知,局部变量的内存通常存储在堆栈中。从函数返回时,释放函数局部变量的内存非常简单 - 它们基本上与函数的堆栈帧一起消失。当它们消失时,它们就会消失:没有办法(在C中)有一些与它们消失有关的动作。特别是,对于恰好是文件描述符的变量,无法调用close()

(如果你想在变量消失时进行清理操作,一种方法是使用C ++,并使用类变量,并定义一个显式的析构函数。)

当您致电malloc时,会出现类似的情况。在这个功能中:

void f()
{
    char *p = malloc(10);
}

我们调用malloc来分配10个字节的内存并将返回的指针存储在本地指针变量p中,当函数f返回时它会消失。所以我们丢失了指向已分配内存的指针,但是没有调用free(),因此内存仍然被分配。 (这是内存泄漏的示例。)