前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >60秒问答:new 底层原理

60秒问答:new 底层原理

作者头像
程序员小王
发布2022-01-11 09:08:02
6320
发布2022-01-11 09:08:02
举报
文章被收录于专栏:架构说架构说

历史回顾

  • 多次次了,每次都失败,自己感觉总结很多了【virtual 函数】
  • 下次别人提出更难问题,还是自己没理解【构造和析构顺序】

本周阅读:深度探索C++对象模型

https://mp.weixin.qq.com/s/pAoIe9m2Oat7d8c_ZW5Qyg

C++对象模型-构造函数语义学

https://mp.weixin.qq.com/s/z246VYFrR9zDzIWZTS5yWA

C++ 对象的内存布局(上) https://coolshell.cn/articles/12176.html

阅读收益

问:一个服务1G,内存,能通过malloc 申请2G内存吗?

第一步:了解参数memory overcommit含义并且测试

  1. 可以做到 man malloc

敲重点:malloc返回的非null 地址,不保证一定可用

The malloc() function allocates size bytes and returns a pointer to the allocated memory.

代码语言:javascript
复制
The memory is not initialized.

 [没有初始化,没有分配物理内存 ,staic 变量]

By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. 【在 Linux 上,malloc永远不会失败。它总是返回一个指向已分配内存的指针,但稍后如果没有足够的物理内存可用,您的应用程序可能会在尝试访问该内存时崩溃。】

In case it turns out that the system is out of memory, one or more processes will be killed by the OOM killer. For more information, see the description of

/proc/sys/vm/overcommit_memory

60秒思考:变量没有初始化 还有哪些用处?为初始化的变量就是弱符号

  • cat /proc/sys/vm/overcommit_memory 0 默认
  • 继续
代码语言:javascript
复制
0 – 这是缺省值 ,采取试试态度:OVERCOMMIT_GUESS【不行就拉到】

可以过度使用swap,意思是说可以申请过大内存,但是不能冥想过大【这个衡量标准不明确】


1 – Always overcommit. 允许overcommit,对内存申请来者不拒。【没有任何限制】

2 – Don’t overcommit. 禁止overcommit。【建议做法】
申请的内存总数超过CommitLimit的话就算是overcommit。
公式如下:
【CommitLimit = (Physical RAM * vm.overcommit_ratio / 100) + Swap】

不超过swap+物理内存的50%


0 - Heuristic overcommit handling. 【过度申请是不行的,邓家 1 】
    Obvious overcommits of
  address space are refused. 
    
    Used for a typical system. 
    Itensures a seriously wild allocation fails while allowing
  overcommit to reduce swap usage.  
    root is allowed to 
  allocate slightly more memory in this mode. 
    
    This is the 
  default.

1 - Always overcommit.【来者不拒】
    Appropriate for some scientific
  applications. Classic example is code using sparse arrays
  and just relying on the virtual memory consisting almost
  entirely of zero pages.

2 - Don't overcommit(超过意思,不是不允许申请过大的). 
 
    The total address space commit
  for the system is not permitted to exceed swap + a
    
  configurable amount (default is 50%) of physical RAM.
  Depending on the amount you use, in most situations
  this means a process will not be killed while accessing
  pages but will receive errors on memory allocation as
  appropriate.


代码语言:javascript
复制
grep -i commit /proc/meminfo
CommitLimit:     1464112 kB 【CommitLimit 就是overcommit的阈值】
Committed_AS:     608060 kB 【已经申请的Committed_As】

  • 为什么配置2 【过度使用内存属于程序问题,不应该os处理,os提示错误】

第2步:问题还原:vm.overcommit_memory=2的测试

2.1 问题还原 内存申请分配失败现象

  • 执行任何命令都错误;bash: fork: 无法分配内存

在2ge 内存的 内存已经不够。

代码语言:javascript
复制

echo 2 >>/proc/sys/vm/overcommit_memory 

cat /proc/sys/vm/overcommit_memory 
结果执行任何sell 命令都报错

cat /proc/sys/vm/overcommit_memory 【shell fork一个进程 exec 】
 s
-bash: fork: 无法分配内存 【shell fork一个进程 exec 】



解决办法:腾讯云主机安全防护(云镜卸载)

/usr/local/qcloud/YunJing/uninst.sh

2.2 问题还原:vm.overcommit_memory=2的测试 证明 malloc 申请失败情况。【慎用】

-bash: fork: 无法分配内存

代码语言:javascript
复制

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 
#include<unistd.h> 
int main() 
{ 
        char* p=NULL; 
        while(1) 
        { 
                p=malloc(sizeof(int)*1000); 
                if(NULL==p) 
                { 
                        break; 
                } 
                /*
                下面的这一句话,保证了申请到的内存都是有效的,可被使用的,在内存分配原则中,就存在一种情况是,如果分配的内存不被使用,可以预先分配并不存在的内存,等待内存被释放,
                */
                memset(p,0x00,100); 
                
                usleep(10); 
        } 
        while(1) 
        { 
                sleep(1); 
        } 
        return 0; 
}

执行任何命令都报错:包括导致无法登陆 情况。这个测试导致服务不可用

代码语言:javascript
复制
[root@VM-0-10-centos demo]# ./a.out 
-bash: fork: 无法分配内存

gcc 33.c
-bash: fork: 无法分配内存

free -m
-bash: fork: 无法分配内存

ls -ltra  /proc [无法删除进程]
-bash: fork: 无法分配内存

 top
-bash: fork: 无法分配内存

shutdown -r now
-bash: fork: 无法分配内存

了解swap:没有开启 vm.overcommit_memory=2的测试情况下 导致失败

  • free 查看 swap =0;

$ free -m

代码语言:javascript
复制
# 输出如下
#               total        used        free      shared  buff/cache   available
# Mem:           7976        4979         328         124        2669        2703
# Swap:             0           0           0
  • vm.overcommit_memory =2 限制很小
  • windows的虚拟内存是电脑自动设置的
  • Linux的swap分区是你装系统的时候分好的 swap是位于磁盘上的特殊文件(或分区),属于“虚拟内存”的一部分

Swap space in Linux is used when the amount of physical memory (RAM) is full

虚拟内存即所谓的 swap

  • 开启

echo 60 >/proc/sys/vm/swappiness

代码语言:javascript
复制
centos开启虚拟内存
1 mkdir /swaps

2 cd /swaps

3   dd if=/dev/zero of=swaps bs=512k count=4096  

 swap大小为bs*count=4096*512/1024/1024=(2G)

4  swapon /swaps/swaps

5 开机挂载

cat /etc/fstab

/swaps/swaps swap swap defaults 0 0

总结 overcommit_memory 三个情况

1 永远允许使用swap

2 超过swap+物理内存 一半 后不允许 【从设置这个最正确,但是慎用,一旦内存泄漏 导致,机器无法登陆情况.一定开启swap】

0 超过swap就失败

敲重点:无论采取那个方式 malloc原理就是虚拟内存(盘上连续一片空间) 和overcommit_memory无关 一定开启swap:

第二步 查看代码 了解参数含义

代码语言:javascript
复制
内核参数 vm.overcommit_memory 的值0,1,2对应的源代码如下,

源文件:
https://github.com/torvalds/linux/blob/master/include/linux/mman.h
 
#define OVERCOMMIT_GUESS                0
#define OVERCOMMIT_ALWAYS               1
#define OVERCOMMIT_NEVER                2

extern int sysctl_overcommit_memory;
extern int sysctl_overcommit_ratio;

https://github.com/torvalds/linux/blob/master/mm/mmap.c

判断什么时候分配物理内存

C++ 新手一般有两个常见的误解:

  1. 任何 class 如果没有被定义 default constructor,就会被合成出来一个;【b没有构造函数】
  2. 编译器合成出来的 default constructor 会明确设定 “class 内 每一个 data member 的 默认值”.【b构造函数枚执行】

在 以下 4 种情况下,编译器会 合成 构造函数

  • case 1 当一个class 中 “带有 default constructor”的 member class object;
  • case 2 当一个class 派生自 ”带有 default constructor“的 base class;
  • case 3 当一个class 声明(或 继承)一个 virtual function;
  • case 4 当一个class 派生自一个 继承串链,其中有一个 或 多个 virtual base class.

当一个 class 中声明了 virtual function 时

  • 编译器会产生 一个 virtual function table,内放 class 的 virtual functions 地址;
  • 在每一个 class object 中,编译器 会 合成 一个 pointer member(即 vptr),用来指向 class 的 vtbl (virtual function table).

https://godbolt.org/z/P5h1Phfn4

  • C++多重继承的构造执行顺序:

构造函数的执行过程会分成两个阶段:

1 初始化阶段

  • 如果是继承的类 ,根据左到右继承顺序,
  • 如果是成员变量,类成员的上到下声明顺序

2 赋值阶段 (构造函数中代码顺序)

代码语言:javascript
复制
1.首先执行虚基类的构造函数,多个虚基类的构造函数按照被继承的顺序构造;【继承的顺序构造】

2.执行基类的构造函数,多个基类的构造函数按照被继承的顺序构造;【继承的顺序构造】

3.执行成员对象的构造函数,多个成员对象的构造函数按照声明的顺序构造;【声明的顺序】
4.执行派生类自己的构造函数;
5.析构以与构造相反的顺序执行;【相反的顺序执行】



结论
在类被构造的时候(有继承和组合),

先执行虚拟继承的父类的构造函数,

然后从左到右执行普通继承的父类的构造函数,

然后按照定义的顺序执行数据成员的初始化,

最后是自身的构造函数的调用。析构函数与之完全相反,互成镜


例子1
代码语言:javascript
复制
继承与列表初始化
下面的例子中B类继承了A和C,然后又拥有一个A和C类型的成员变量,虽然不符合设计模式,但是就将就看了。

#include <iostream>
 #include <cmath>
 using namespace std;

 class A
 {
 public:
  A(){cout << "Construct A" << endl;}
  ~A(){cout << "Destruct A" << endl;}
 };

 class C
 {
 public:
  C(){cout << "Construct C" << endl;}
  ~C(){cout << "Destruct C" << endl;}
  
 };

 class B: public A, public C
 {
 public:
  //Notice: List initialize
  B(): a(A()), c(C()) {cout << "Construct B" << endl;}
  ~B(){cout << "Destruct B" << endl;}
  C c;
  A a;
 };

 int main(int argc, char const *argv[])
 {
  B b;
  return 0;
 }

在这样的例子中输出是这样的~

  • 构造顺序 Construct A //左到右继承顺序 Construct C //左到右继承顺序 Construct C //类成员的上到下声明顺序 Construct A /类成员的上到下声明顺序 Construct B //自己 Destruct A //类成员的下到上声明顺序 Destruct C //类成员的下到上声明顺序 Destruct C //右到左到继承顺序 Destruct A//右到左到继承顺序
    • 析构以与构造相反的顺序执行 Destruct B //自己

例子2

https://www.cnblogs.com/GyForever1004/p/8439397.html

巨人肩膀

  1. https://www.etalabs.net/overcommit.html
  2. https://www.cnblogs.com/GyForever1004/p/8439397.html
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Offer多多 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 历史回顾
  • 阅读收益
    • 第一步:了解参数memory overcommit含义并且测试
      • 第2步:问题还原:vm.overcommit_memory=2的测试
        • 2.1 问题还原 内存申请分配失败现象
        • 2.2 问题还原:vm.overcommit_memory=2的测试 证明 malloc 申请失败情况。【慎用】
      • 了解swap:没有开启 vm.overcommit_memory=2的测试情况下 导致失败
        • 总结 overcommit_memory 三个情况
      • 第二步 查看代码 了解参数含义
        • 判断什么时候分配物理内存
          • 例子2
      • 巨人肩膀
      相关产品与服务
      云服务器
      云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档