https://mp.weixin.qq.com/s/pAoIe9m2Oat7d8c_ZW5Qyg
https://mp.weixin.qq.com/s/z246VYFrR9zDzIWZTS5yWA
C++ 对象的内存布局(上) https://coolshell.cn/articles/12176.html
问:一个服务1G,内存,能通过malloc 申请2G内存吗?
敲重点:malloc返回的非null 地址,不保证一定可用
The malloc() function allocates size bytes and returns a pointer to the allocated memory.
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秒思考:变量没有初始化 还有哪些用处?为初始化的变量就是弱符号
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.
grep -i commit /proc/meminfo
CommitLimit: 1464112 kB 【CommitLimit 就是overcommit的阈值】
Committed_AS: 608060 kB 【已经申请的Committed_As】
在2ge 内存的 内存已经不够。
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
-bash: fork: 无法分配内存
#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;
}
执行任何命令都报错:包括导致无法登陆 情况。这个测试导致服务不可用
[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: 无法分配内存
$ free -m
# 输出如下
# total used free shared buff/cache available
# Mem: 7976 4979 328 124 2669 2703
# Swap: 0 0 0
Swap space in Linux is used when the amount of physical memory (RAM) is full
虚拟内存即所谓的 swap
echo 60 >/proc/sys/vm/swappiness
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
1 永远允许使用swap
2 超过swap+物理内存 一半 后不允许 【从设置这个最正确,但是慎用,一旦内存泄漏 导致,机器无法登陆情况.一定开启swap】
0 超过swap就失败
敲重点:无论采取那个方式 malloc原理就是虚拟内存(盘上连续一片空间) 和overcommit_memory无关 一定开启swap:
内核参数 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++ 新手一般有两个常见的误解:
在 以下 4 种情况下,编译器会 合成 构造函数
当一个 class 中声明了 virtual function 时
https://godbolt.org/z/P5h1Phfn4
构造函数的执行过程会分成两个阶段:
1 初始化阶段
2 赋值阶段 (构造函数中代码顺序)
1.首先执行虚基类的构造函数,多个虚基类的构造函数按照被继承的顺序构造;【继承的顺序构造】
2.执行基类的构造函数,多个基类的构造函数按照被继承的顺序构造;【继承的顺序构造】
3.执行成员对象的构造函数,多个成员对象的构造函数按照声明的顺序构造;【声明的顺序】
4.执行派生类自己的构造函数;
5.析构以与构造相反的顺序执行;【相反的顺序执行】
结论
在类被构造的时候(有继承和组合),
先执行虚拟继承的父类的构造函数,
然后从左到右执行普通继承的父类的构造函数,
然后按照定义的顺序执行数据成员的初始化,
最后是自身的构造函数的调用。析构函数与之完全相反,互成镜
继承与列表初始化
下面的例子中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;
}
在这样的例子中输出是这样的~
https://www.cnblogs.com/GyForever1004/p/8439397.html