不同的数据在内存中有不同的保存时机、保存位置。在执行程序时,总内存会被分为多个段,称为文本,未初始化的全局、初始化的全局、栈和堆段。将整个程序加载到文本段中,并在堆栈存储器中选择存储器到变量。
High Addresses ---> .----------------------.| Environment ||----------------------|| | Functions and variable are declared| STACK | on the stack.base pointer -> | - - - - - - - - - - -|| | || v |: :. . The stack grows down into unused space. Empty . while the heap grows up. . .. . (other memory maps do occur here, such . . as dynamic libraries, and different memory: : allocate)| ^ || | |brk point -> | - - - - - - - - - - -| Dynamic memory is declared on the heap| HEAP || ||----------------------|| BSS | Uninitialized data (BSS)|----------------------| | Data | Initialized data (DS)|----------------------|| Text | Binary code
Low Addresses ----> '----------------------'
此段包含所有未初始化的全局和静态变量,所有变量都由零或者空指针初始化。程序加载器在加载程序时为BSS节分配内存。
此段包含显式初始化的全局变量和静态变量,大小由程序源代码中值的大小决定,在运行时不会更改。它具有读写权限,因此可以在运行时更改此段的变量值。
该段是一个只读段,包含已编译程序的二进制文件。该段是可共享的,因此对于文本编辑器等频繁执行的程序,内存中只需要一个副本
#include
class A
{
public:int a;A() : a(0x1) {}virtual void foo() { std::cout << "A::foo()" << std::endl; }void bar() { std::cout << "A::bar()" << std::endl; }
};class B : public A
{
public:int b;B() : A(), b(0x2) {}void foo() { std::cout << "B::foo()" << std::endl; }
};class C : public B
{
public:int c;C() : B(), c(0x3) {}void foo() { std::cout << "C::foo()" << std::endl; }
};int main(int argc, char **argv)
{A a;B b;C c;B *p = &c;p->foo();std::cout << sizeof(int) << " " << sizeof(int *) << std::endl;return 0;
}
g++ main.cpp -o main -std=c++14 -g
gdb查看
(gdb) b 29
Breakpoint 1 at 0x120b: file main.cpp, line 29.
(gdb) r
Breakpoint 1, main (argc=1, argv=0x7fffffffdd48) at main.cpp:29
29 A a;
(gdb) n
30 B b;
(gdb) set print pretty on
(gdb) set print vtbl on
(gdb) p a
$1 = {_vptr.A = 0x555555557d38 ,a = 1
}
(gdb) p/a &a
$2 = 0x7fffffffdbf0
(gdb) p/a &a.a
$3 = 0x7fffffffdbf8
(gdb) p sizeof(a)
$4 = 16
(gdb) x/2xg &a
0x7fffffffdbf0: 0x0000555555557d38 0x00007fff00000001
(gdb) info vtbl a
vtable for 'A' @ 0x555555557d38 (subobject @ 0x7fffffffdbf0):
[0]: 0x555555555344
gdb查看
(gdb) n
31 C c;
(gdb) p b
$6 = { = {_vptr.A = 0x555555557d20 ,a = 1}, members of B:b = 2
}
(gdb) p sizeof(b)
$7 = 16
(gdb) n
32 B *p = &c;
(gdb) p c
$8 = { = { = {_vptr.A = 0x555555557d08 ,a = 1}, members of B:b = 2}, members of C:c = 3
}
(gdb) p sizeof(c)
$9 = 24
(gdb) info vtbl b
vtable for 'B' @ 0x555555557d20 (subobject @ 0x7fffffffdc00):
[0]: 0x5555555553ba
(gdb) info vtbl c
vtable for 'C' @ 0x555555557d08 (subobject @ 0x7fffffffdc10):
[0]: 0x555555555430
如果class B中申明了新的虚函数(比如foo2),class B中依然只有一个虚函数表,只不过会把foo2加入到该表中。此时class A的虚函数表不会包含foo2。
#include class A
{int a;virtual void foo() { std::cout << "A::foo()" << std::endl; }
};class B
{int b;virtual void bar() { std::cout << "B::bar()" << std::endl; }
};class C : public A, public B
{int c;void foo() { std::cout << "C::foo()" << std::endl; }void bar() { std::cout << "C::bar()" << std::endl; }
};int main(int argc, char **argv)
{A a;B b;C c;std::cout << sizeof(int) << " " << sizeof(int *) << std::endl;return 0;
}
gdb查看
gdb main
(gdb) b 28
Breakpoint 1 at 0x122f: file main.cpp, line 28.
(gdb) set print pretty on
(gdb) set print vtbl on
(gdb) set print object on
(gdb) p a
No symbol "a" in current context.
(gdb) r
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".Breakpoint 1, main (argc=1, argv=0x7fffffffdd48) at main.cpp:28
28 std::cout << sizeof(int) << " " << sizeof(int *) << std::endl;
(gdb) p a
$1 = (A) {_vptr.A = 0x555555557d20 ,a = -134528544
}
(gdb) p b
$2 = (B) {_vptr.B = 0x555555557d08 ,b = -135408993
}
(gdb) p/a c
$3 = (C) { = {_vptr.A = 0x555555557cd0 ,a = 0xfffffffff7eab60a}, = {_vptr.B = 0x555555557cf0 ,b = 0xfffffffff7fb3e88}, members of C:c = 0x7fff
--Type for more, q to quit, c to continue without paging--
}
(gdb) p sizeof(c)
$4 = 32
(gdb) x/5ag &c
0x7fffffffdc00: 0x555555557cd0 <_ZTV1C+16> 0x7ffff7eab60a <_ZNSt9basic_iosIwSt11char_traitsIwEE15_M_cache_localeERKSt6locale+90>
0x7fffffffdc10: 0x555555557cf0 <_ZTV1C+48> 0x7ffff7fb3e88 <_ZSt5wclog+8>
0x7fffffffdc20: 0x7ffff7fb3940
#include class A
{int a;virtual void foo() { std::cout << "A::foo()" << std::endl; }
};class B : virtual public A
{int b;virtual void foo() { std::cout << "B::foo()" << std::endl; }
};class C : virtual public A
{int c;void foo() { std::cout << "C::foo()" << std::endl; }
};class D : public B, public C
{int d;virtual void foo() { std::cout << "D::foo()" << std::endl; }
};int main(int argc, char **argv)
{A a;B b;C c;D d;A *pa = &d;B *pb = &d;C *p c = &d;std::cout << sizeof(int) << " " << sizeof(int *) << std::endl;return 0;
}
gdb查看
gdb main
(gdb) b 37
Breakpoint 1 at 0x1247: file main.cpp, line 37.
(gdb) r
37 std::cout << sizeof(int) << " " << sizeof(int *) << std::endl;
(gdb) set print pretty on
(gdb) set print object on
(gdb) set print vtbl on
(gdb) p a
$1 = (A) {_vptr.A = 0x555555557ce0 ,a = 0
}
(gdb) p b
$2 = (B) { = {_vptr.A = 0x555555557cb8 ,a = -238370304}, members of B:_vptr.B = 0x555555557c98 ,b = 0
--Type for more, q to quit, c to continue without paging--
}
(gdb) p c
$3 = (C) { = {_vptr.A = 0x555555557c68 ,a = -134528544}, members of C:_vptr.C = 0x555555557c48 ,c = -134529192
}
(gdb) p d
$4 = (D) { = { = {_vptr.A = 0x555555557b70 ,a = -134529400}, members of B:_vptr.B = 0x555555557b30 ,b = -135408993}, = {members of C:_vptr.C = 0x555555557b50 ,c = -135612918}, members of D:d = 32767
}
(gdb) p &d
$5 = (D *) 0x7fffffffdbf0