博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
学习几个“××在内存中占几份”的若干问题
阅读量:5985 次
发布时间:2019-06-20

本文共 2317 字,大约阅读时间需要 7 分钟。

  • 先需要明白一个问题:

COW:写时复制,即:Copy-on-Write,当写入时,进行拷贝:

无写入操作:共用一份内存

有写入操作:拷贝该块出来供修改,并改变进程的内存地址映射,使之映射到到新的内存块地址

这是一种内存优化策略,因为,当同一个EXE,或者同一个DLL执行的时候,程序段自然都是相同的;而在调用函数的时候压入栈的数据段,有可能也是相同的,假如确实是相同的,则操作系统会将不同的进程的相同内存块的部分映射到同一地址,其实,程序的执行无论代码或者数据,都是基于地址的,操作系统则可以通过合理的管理这些地址,进行内存空间的优化。还有另一种情况是,假如数据段被某个或者某些进程修改了怎么办呢?此时,会根据COW原则,对有修改操作的进程,将它们对该内存的控制权取消,转移到另一块内存去进行操作,避免造成共享内存数据的不一致性。关于全局函数和静态变量,他们在下面这个问题上是等价的:就是只能在一个进程内部共享,而不会和另一个进程共享,因此,不同进程对于同一个DLL中全局或者静态变量的修改,会导致系统给它专门分配一块新的空间出来。

  • 那么就有一个问题了:

如何通过一个DLL去实现进程间的数据共享呢?

有一种声明,导出,载入共享数据段的方式,但是似乎这种方法并不可行,或者说,最起码,不被推崇。

而最受欢迎的是mmap/munmap方法,多个进程,将同一个文件,映射到内存,此时,他们能(宏观上)同时对该内存进行读写操作,进而完成数据共享。

  • 虚函数,静态函数,成员函数:是否放在代码区同等的位置:

是的,都放在类作用域内(区别于对象的作用域:对象的作用域是指对象所占的堆栈空间);类的作用域空间无非是该类的常量空间,静态变量空间,代码空间(唯独没有堆栈等数据空间)。

由此也可知一个问题:内存分为堆、栈、代码、静态、常量,共五类空间。

  • static函数的问题:

另一个问题:类中static函数的问题:非static函数都会使用__thiscall方法调用,该方法实质会传入this指针作为参数,将函数中的变量重新映射到实例对应的数据区,从而对实例的成员变量进行访问;然而,static方法不会传入this指针,因此他无法访问成员函数,虚函数必须能访问虚函数表,这个表指针是存放在实例空间中的,因此虚函数不能是static方法,否则无法访问虚函数表。

  • 虚函数表具体存放在什么位置:

存放在类作用域的常量区。

  • 那些数据是放在类作用域的内存空间,那些数据是放在对象的内存空间:

成员函数代码,静态函数代码,虚函数代码,静态变量,常量,虚函数表:存放在类定义区;

虚函数表指针,成员变量:放在对象实例区。

做个实验:

修改两个不同类的“虚函数表指针”,看看是否如期望的那样:对象初始的4个字节存放“虚函数表”

代码:

1 #include 
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 A20 {21 public:22 int foo()23 {24 printf("B\n");25 return 2;26 }27 };28 29 class C : public A30 {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虚函数表指针被修改了!请按任意键继续. . .

 

>>转载请注明出处<<

转载于:https://www.cnblogs.com/zanzan101/p/3383462.html

你可能感兴趣的文章
Citrix VDI实战攻略之八:测试验收
查看>>
windows下安装memcached
查看>>
Java读取properties文件的思考
查看>>
分秒必争域的时间同步问题[为企业部署Windows Server 2008系列十四]
查看>>
IronRuby:请教如何在DOS窗口正确显示UTF-8字符后执行bat文件呢?
查看>>
关于设置SQLPLUS提示符样式的方法
查看>>
厕所老鼠和粮仓老鼠
查看>>
算法与数据结构:C语言的整数数组全排列(源码)
查看>>
arcengine,深入理解游标Cursors,实现数据的快速查找,插入,删除,更新
查看>>
你可能不知道的10 个JavaScript 小技巧[转]
查看>>
Content-Script-Type的设置好象没多大用处,或许我不知道有什么用
查看>>
获取URL最后一个 ‘/’ 之后的字符
查看>>
Win32程序和控制台应用程序的项目互转设置
查看>>
python 线性回归示例
查看>>
Linux 小知识翻译 - 「SCP和SFTP」
查看>>
漫画:面试过程的神回复
查看>>
Android开发之旅:HelloWorld项目的目录结构
查看>>
关于Java异常和错误的几个问题
查看>>
MongoDB初学
查看>>
Design4:数据库设计规范
查看>>