7

I've recently decided to learn more about systems programming, and felt it would be helpful to see what my code is actually doing under the hood.

To do this, I wrote a short LinkedList class in C++ and decided to trace it using dtruss (read: dtrace).

My expectation was that any instructions that extend the heap (e.g. using the new keyword, or instantiating LinkedList objects) would invoke the mmap or sbrk/break system calls. This was not the case!

In fact, running dtruss with the -s switch, I don't see any system calls being invoked from inside my LinkedList::Add function! Testing, I'm certain elements are being added.

Can anyone explain why I don't see references to mmap/sbrk in my dtruss output?

Bonus points if someone could explain the purpose of mprotect and madvise.

I've included my LinkedList class, main.cpp, and dtruss output below.

Thank you!

dtruss output

SYSCALL(args)        = return
Created new LinkedList
Created new LinkedList
Destroyed a LinkedList
open("/dev/dtracehelper\0", 0x2, 0xFFFFFFFFE3236D70)         = 3 0
ioctl(0x3, 0x80086804, 0x7FFEE3236CD0)       = 0 0
close(0x3)       = 0 0
access("/AppleInternal/XBS/.isChrooted\0", 0x0, 0x0)         = -1 Err#2
thread_selfid(0x0, 0x0, 0x0)         = 198178 0
bsdthread_register(0x7FFF5BAB5C50, 0x7FFF5BAB5C40, 0x2000)       = 1073742047 0
issetugid(0x0, 0x0, 0x0)         = 0 0
mprotect(0x10C9D0000, 0x1000, 0x0)       = 0 0
mprotect(0x10C9D5000, 0x1000, 0x0)       = 0 0
mprotect(0x10C9D6000, 0x1000, 0x0)       = 0 0
mprotect(0x10C9DB000, 0x1000, 0x0)       = 0 0
mprotect(0x10C9CE000, 0x88, 0x1)         = 0 0
mprotect(0x10C9DC000, 0x1000, 0x1)       = 0 0
mprotect(0x10C9CE000, 0x88, 0x3)         = 0 0
mprotect(0x10C9CE000, 0x88, 0x1)         = 0 0
getpid(0x0, 0x0, 0x0)        = 1698 0
stat64("/AppleInternal/XBS/.isChrooted\0", 0x7FFEE32362E8, 0x0)      = -1 Err#2
stat64("/AppleInternal\0", 0x7FFEE3236380, 0x0)      = -1 Err#2
csops(0x6A2, 0x7, 0x7FFEE3235E20)        = -1 Err#22
sysctl([CTL_KERN, 14, 1, 1698, 0, 0] (4), 0x7FFEE3235F68, 0x7FFEE3235F60, 0x0, 0x0)      = 0 0
csops(0x6A2, 0x7, 0x7FFEE3235710)        = -1 Err#22
getrlimit(0x1008, 0x7FFEE32374F0, 0x0)       = 0 0
fstat64(0x1, 0x7FFEE3237508, 0x0)        = 0 0
ioctl(0x1, 0x4004667A, 0x7FFEE3237554)       = 0 0
write_nocancel(0x1, "Created new LinkedList\n\0", 0x17)      = 23 0
write_nocancel(0x1, "Created new LinkedList\n\0", 0x17)      = 23 0
write_nocancel(0x1, "Destroyed a LinkedList\n\0", 0x17)      = 23 0

LinkedList.cpp

#include <iostream>
#include "LinkedList.h"

using namespace std;

LinkedList::LinkedList() {
    this->length = 0;
    this->head = NULL;
    this->tail = NULL;
    cout << "Created new LinkedList" << endl;
}

LinkedList::~LinkedList() {
    Node* curr;
    Node* temp;
    curr = this->head;

    while ( curr ) {
        temp = curr;
        curr = curr->next;
        delete temp;
    }

    cout << "Destroyed a LinkedList" << endl;
}

void LinkedList::Add(int v) {

    Node* n = new Node();
    n->val = v;
    n->next = NULL;

    if (!this->head) {
        this->head = n;
        this->tail = n;
    } else {
        this->tail->next = n;
        this->tail = n;
    }    
}

main.cpp

#include <iostream>
#include "LinkedList.h"

using namespace std;

int main() {

    LinkedList l; // You should require a heap increase, right?

    LinkedList* ll = new LinkedList(); // Surely you require more heap!

    for (int i=0; i<1000; i++) 
        l.Add(i);

    return 0;

}
4

1 回答 1

5

我发现 Mac OSsbrk/brk/break()不像大多数 UNIX/Linux 那样用于内存管理。基本上,它使用 Apple 从 NeXT 继承的 Mach 内核,因此内存调用将是mpadvise(2)并且mprotect(2)提供比sbrk().

来自 Jonathan Levin 的“Mac OS X 和 iOS 内部”:

在此处输入图像描述

因此,要解释您的内存分配,您需要知道标头中的mprotect(2)参数sys/mman.h

#define PROT_NONE       0x00    /* [MC2] no permissions */
#define PROT_READ       0x01    /* [MC2] pages can be read */
#define PROT_WRITE      0x02    /* [MC2] pages can be written */
#define PROT_EXEC       0x04    /* [MC2] pages can be executed */
....

所以你的系统调用意味着:

mprotect(0x10C9D0000, 0x1000, 0x0)       = 0 0
mprotect(0x10C9D5000, 0x1000, 0x0)       = 0 0
mprotect(0x10C9D6000, 0x1000, 0x0)       = 0 0
mprotect(0x10C9DB000, 0x1000, 0x0)       = 0 0
mprotect(0x10C9CE000, 0x88, 0x1)         = 0 0  <-- Allow reads starting at 0x10C9CE000 for 136 bytes
mprotect(0x10C9DC000, 0x1000, 0x1)       = 0 0
mprotect(0x10C9CE000, 0x88, 0x3)         = 0 0  <-- Allow reads and writes starting at 0x10C9CE000 for 136 bytes
mprotect(0x10C9CE000, 0x88, 0x1)         = 0 0

关于mmap(2),在 Linux 系统上,它用于映射共享库的目标代码,但不用于malloc/freeor new/delete

参考:

于 2018-04-13T23:35:55.907 回答