- 先需要明白一个问题:
COW:写时复制,即:Copy-on-Write,当写入时,进行拷贝:
无写入操作:共用一份内存
有写入操作:拷贝该块出来供修改,并改变进程的内存地址映射,使之映射到到新的内存块地址
这是一种内存优化策略,因为,当同一个EXE,或者同一个DLL执行的时候,程序段自然都是相同的;而在调用函数的时候压入栈的数据段,有可能也是相同的,假如确实是相同的,则操作系统会将不同的进程的相同内存块的部分映射到同一地址,其实,程序的执行无论代码或者数据,都是基于地址的,操作系统则可以通过合理的管理这些地址,进行内存空间的优化。还有另一种情况是,假如数据段被某个或者某些进程修改了怎么办呢?此时,会根据COW原则,对有修改操作的进程,将它们对该内存的控制权取消,转移到另一块内存去进行操作,避免造成共享内存数据的不一致性。关于全局函数和静态变量,他们在下面这个问题上是等价的:就是只能在一个进程内部共享,而不会和另一个进程共享,因此,不同进程对于同一个DLL中全局或者静态变量的修改,会导致系统给它专门分配一块新的空间出来。
- 那么就有一个问题了:
如何通过一个DLL去实现进程间的数据共享呢?
有一种声明,导出,载入共享数据段的方式,但是似乎这种方法并不可行,或者说,最起码,不被推崇。
而最受欢迎的是mmap/munmap方法,多个进程,将同一个文件,映射到内存,此时,他们能(宏观上)同时对该内存进行读写操作,进而完成数据共享。
- 虚函数,静态函数,成员函数:是否放在代码区同等的位置:
是的,都放在类作用域内(区别于对象的作用域:对象的作用域是指对象所占的堆栈空间);类的作用域空间无非是该类的常量空间,静态变量空间,代码空间(唯独没有堆栈等数据空间)。
由此也可知一个问题:内存分为堆、栈、代码、静态、常量,共五类空间。
- static函数的问题:
另一个问题:类中static函数的问题:非static函数都会使用__thiscall方法调用,该方法实质会传入this指针作为参数,将函数中的变量重新映射到实例对应的数据区,从而对实例的成员变量进行访问;然而,static方法不会传入this指针,因此他无法访问成员函数,虚函数必须能访问虚函数表,这个表指针是存放在实例空间中的,因此虚函数不能是static方法,否则无法访问虚函数表。
- 虚函数表具体存放在什么位置:
存放在类作用域的常量区。
- 那些数据是放在类作用域的内存空间,那些数据是放在对象的内存空间:
成员函数代码,静态函数代码,虚函数代码,静态变量,常量,虚函数表:存放在类定义区;
虚函数表指针,成员变量:放在对象实例区。
做个实验:
修改两个不同类的“虚函数表指针”,看看是否如期望的那样:对象初始的4个字节存放“虚函数表”
代码:
1 #include <stdlib.h> 2 3 /*** 4 * @author:zanzan101 5 */ 6 7 class A 8 { 9 private: 10 int data; 11 public: 12 virtual int foo() 13 { 14 printf("A\n"); 15 return 1; 16 } 17 }; 18 19 class B : public A 20 { 21 public: 22 int foo() 23 { 24 printf("B\n"); 25 return 2; 26 } 27 }; 28 29 class C : public A 30 { 31 public: 32 int foo() 33 { 34 printf("C\n"); 35 return 3; 36 } 37 }; 38 39 void func(const char* str) 40 { 41 printf("%s\n", str); 42 } 43 44 typedef void (*ptr_of_func)(const char *); // 这是个类型定义 45 ptr_of_func p = func; // 这是个变量声明及初始化 46 47 // 分开操作则报错 48 // ptr_of_func q; 49 // q = func; 50 51 int main() 52 { 53 C c; 54 B b; 55 A* ptr = &b; 56 if(2 == ptr->foo()) 57 p("多态:调用了B的函数!"); 58 59 // 修改B的对象的前4个字节的数据为C对象的前4个字节的数据 60 p("修改B的对象的前4个字节的数据为C对象的前4个字节的数据"); 61 memcpy(&b, &c, sizeof(void*)); 62 63 if(3 == ptr->foo()) 64 p("虚函数表指针被修改了!"); 65 66 system("pause"); 67 return 0; 68 }
输出:
B
多态:调用了B的函数!
修改B的对象的前4个字节的数据为C对象的前4个字节的数据
C
虚函数表指针被修改了!
请按任意键继续. . .
>>转载请注明出处<<