Linux 大页内存 Huge Pages 虚拟内存

news2024/11/16 7:52:29

Linux 大页内存 Huge Pages 虚拟内存 - 秋来叶黄 - 博客园 (cnblogs.com)

Linux为什么要有大页内存?为什么DPDK必须要设置大页内存?这都是由系统架构决定的。一开始为了解决一个问题,设计了对应的方案,随着事物的发展,无法满足新的需求,就在原来的基础上改进,慢慢的变成了现在的样子。

物理内存 Physical address

物理内存就是电脑的内存条,上面的每一个方块就是存储芯片,芯片中还有颗粒。访问数据的时候,会使用各种技术,尽可能从多个内存条,每个内存条的多个存储芯片获取数据,这样多通道,并发大,速度更快。

虚拟内存 Linear address (also known as virtual address)

程序运行在操作系统上,不可能直接访问物理内存。一是太复杂,需要自己管理内存,哪些被其他进程占用了,哪些可以用,如果连续空间不够,如何拼接等;二是不安全,用户可以直接访问到其他进程的数据。所以操作系统在后续增加了虚拟内存的概念。

每个进程看到的都是整个可用内存,比如4G,所有进程看到的都是4G,自己进程维护一张表,当进程访问内存时,只能访问到虚拟内存表,由操作系统再映射到具体的物理内存。这样的好处除了解决了上面的问题,还有几个优点:一是系统同一管理,更合理,可以做更多优化,比如同一块数据多个进程读取,只需要在内存保存一份即可,节省了空间(类库的加载);二是程序申请内存,并不一定会使用,或者说不会立马使用,那么系统可以不分配物理内存,当程序真正访问内存时,触发中断,系统再映射到物理内存,节省资源;三是程序访问的都是连续资源,具体内存分配是由系统管理,简化了开发。

MMU Memory Management Unit 内存管理单元

用来把虚拟内存地址转化为物理内存地址的硬件,提供物理内存数据访问和权限控制。

页表 虚拟内存表

虚拟内存向物理内存映射时,需要创建数据结构保存对应的数据,如果完全一一映射,肯定会需要很多资源,所以为了减少内存空间的消耗,又提出了新的方案:把内存分为一块块的数据(每块称作为一页数据),然后映射这些块,这样就可以减少映射条目,降低内存占用。虚拟内存往往称作页;物理内存按照同样大小分割,有时候称作块或者帧(frame)

MMU存储的针对这些内存页的表,称作为页表。页表中每一条数据保存了映射的物理内存页的位置和在该页内数据的偏移,这样就能找到具体的内存单元了。

除了这种使用页表的页式管理方式,还有段式和段页式两种。

多级分页

使用页表后,数据量还是很大,比如32G的内存,使用4K作为一页,那么需要8,388,608个页表条目。为了进一步减少资源消耗,我们发现大部分程序是不需要全部内存的,一个应用运行起来,并不是必须要32G的内存,有可能只有几百兆。多级分页就做了进一步优化:

比如32G,每级页表按照1G分,有32条记录;1G再按照10M分,就有100条记录,以此类推。开始只创建第一张表,后续需要的时候,再动态创建其他的表,大大减少了页表的记录数。

Translation Lookaside Buffer TLB

多级分页后,数据量少了,但是增加了一个问题,就是访问效率,原来直接访问内存,只需要一次;增加了页表后,需要两次,先访问页表,再访问物理内存;多级页表,需要多次。这相当于成倍的增加了访问内存的时间。TLB就是为了解决这个问题的,把常用的页表,放到CPU的高速缓存,避免访问内存,直接在缓存中获取,提高效率。

大页内存

我们知道,计算机中每个硬件的运算速度是不一样的,其顺序就是:硬盘/网络(IO) < 内存 < 内存缓存(如果有) < CPU L3(CPU3级缓存) < CPU L2 < CPU L1 < CPU,每个之间的差距都是几倍甚至几十上百倍的,同样其空间大小也是相差数量级的,只不过正好反过来。硬盘可以做到TB甚至PB,内存常见的只有几十GB或者几百GB,而CPU的缓存,3级的可能有几十兆,而1级的往往只有字节级别的了。由于这个原因,TLB是不可能把所有的页表都映射到缓存中,那么在CPU缓存中的TLB命中率越高,性能提升越大。如果命中率很低,不仅没有提升,还额外增加了缓存的访问,反而降低了效率。

如果程序频繁的访问一块很大的内存,并且是无序的,比如频繁搜索一个100G的无规律的文本数据,这个时候就会导致CPU中的缓存频频失效,因为CPU缓存的页表条目有限,程序使用的条目超出了缓存TLB的范围,就会不断的删除旧的,加入新的,实际上如果缓存足够大,会发现刚删除的条目又被加了进来。

还有种情况,比如程序需要保存的数据都比较大,每次申请都是2M,而系统默认是4K,需要2048/4=512个条目映射,如果把内存颗粒度设为2M,那么只需要一个,大大减少了查找的次数。

如何解决呢?就是提高命中率,怎样提高命中率呢?就是TLB中保存的数据条目虽然固定,但是每条对应的内存大小可以增加。如果增加TLB映射的内存大小,让其可以覆盖程序读取的范围,这样不管如何乱序访问,都可以命中了。比如原来TLB保存100条,由于一页4K,按照最简单计算,就是400K的空间。我把一页设置为4M,那就可以表示400M的空间,如果程序访问的内存在400M以内,就可以完全命中。

Linux大页内存有两种2MB和1GB。2MB默认支持,1GB可以通过cat /proc/cpuinfo|grep pdpe1gb查看是否支持。实际上大页内存的支持与CPU架构有关,x86_64支持的是2MB和1GB。

查看大页内存

cat /proc/meminfo|grep -i huge
AnonHugePages:      4096 kB
ShmemHugePages:        0 kB
HugePages_Total:       4
HugePages_Free:        2
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:    1048576 kB
Hugetlb:         4194304 kB

配置大页内存 方法一 修改grub

直接修改(不建议)

grub的文件位置在/boot目录下,大部分有如下两个地方,一个是Legacy,一个是UEFI,不同系统可能有细微区别:/boot/grub2/grub.cfg /boot/efi/EFI/openEuler/grub.cfg。打开文件,找到如下位置

 menuentry 'openEuler (4.19.90-2003.4.0.0036.oe1.x86_64) 20.03 (LTS)' --class openeuler --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-4.19.90-2003.4.0.0036.oe1.x86_    64-advanced-db3b87ac-c948-4347-b1a4-e8ca943688b6' {
     load_video
     set gfxpayload=keep
     insmod gzio
     insmod part_msdos
     insmod ext2
     set root='hd0,msdos1'
     if [ x$feature_platform_search_hint = xy ]; then
       search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1'  75039a04-9431-47c8-923c-795ba2b37e3e
     else
       search --no-floppy --fs-uuid --set=root 75039a04-9431-47c8-923c-795ba2b37e3e
     fi
     linux   /vmlinuz-4.19.90-2003.4.0.0036.oe1.x86_64 root=/dev/mapper/openeuler-root ro resume=/dev/mapper/openeuler-swap rd.lvm.lv=openeuler/root rd.lvm.lv=openeuler/swap rhgb quiet quiet crashkernel=51    default_hugepagesz=1G hugepagesz=1G hugepages=4
     initrd /initramfs-4.19.90-2003.4.0.0036.oe1.x86_64.img
 }

在倒数第二行增加default_hugepagesz=1G hugepagesz=1G hugepages=4,这三个字段分别表示默认大页内存大小,就是如果不配置,就用这个默认配置;配置的大页内存大小;配置的大页内存个数。重启系统,再次查看就可以看到大页内存信息。

注意 按照官方建议1GB的大页内存必须在grub设置,开机直接启用,不可在后续配置。
1. Getting Started — Soft Patch Panel 18.08.1 documentation

修改/etc/default/grub

打开/boot/grub2/grub.cfg,找到GRUB_CMDLINE_LINUX,增加对应参数,执行grub2-mkconfig -o /boot/grub2/grub.cfg,重启系统。

修改/etc/default/grub

打开/boot/grub2/grub.cfg,找到GRUB_CMDLINE_LINUX,增加对应参数,执行grub2-mkconfig -o /boot/grub2/grub.cfg,重启系统。

挂载大页内存

#查看是否挂载
mount|grep hugetlbfs
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime,pagesize=1024M)
nodev on /mnt/huge type hugetlbfs (rw,relatime,pagesize=1024M)

#挂载大页内存
mount -t hugetlbfs nodev /mnt/huge
mount -t hugetlbfs hugetlbfs /mnt/huge

#或者使用一条命令挂载
mount -t hugetlbfs nodev /mnt/huge

#也可以修改fstab,让系统启动时自动挂载
vim /etc/fstab
nodev /mnt/huge hugetlbfs pagesize=1GB 0 0

必须保证目录/mnt/huge存在,参数意义:-t指定挂载格式,hugetlbfs表示是大页内存,后面表示挂载设备,可以写hugetlbfs,也可以写nodev不挂载设备,最后是挂载目录

 

NUMA

为什么需要了解NUMA呢?因为与上面的大页内存配置有关。了解NUMA,又需要先知道SMP(Symmetric Multi-Processor)对称多处理器结构。SMP就是指系统中多个CPU对称工作,每个CPU的优先级一样,访问资源(内存)速度一样,没有主次之分。SMP又叫做UMA(Uniform Memory Access)一致内存访问。

但是随着CPU的发展,内核越来越多,访问同一资源的竞争越来越大,导致CPU性能受到限制,所以推出了NUMA(Non Uniform Memory Access)非一致内存访问架构。

NUMA设计

SMP或者UMA,CPU统一经过北桥(内存控制器)访问内存。
NUMA,CPU把内存控制器做到CPU内部,一般一个CPU socket一个。每个CPU内部的内存控制器与一部分内存连接。CPU访问自己连接的内存,速度很快,叫做本地内存,可以通过QPI(Quick Path Interconnect)总线访问其他的内存,不过速度会慢。

Node Socket Core Processor

把多个core封装到一起,叫做一个CPU Socket,系统中根据Socket定义Node,也就是正常情况Node数量与Socket相同,或者一个是软件概念,一个是硬件概念。

Core就是物理CPU,原来是单CPU,性能不够,研发了多CPU架构,现在一个Core就相当于原来的一块CPU

Thread,也叫做逻辑CPU,或者Processor,是把core通过超线程记录模拟出来的处理单元。

lscpu
lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                12
On-line CPU(s) list:   0-11
Thread(s) per core:    1
Core(s) per socket:    6
Socket(s):             2
NUMA node(s):          2
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 45
Stepping:              7
CPU MHz:               1200.000
BogoMIPS:              3999.47
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              15360K
NUMA node0 CPU(s):     0-5
NUMA node1 CPU(s):     6-11

CPU(s) 表示逻辑CPU个数
Thread(s) per core 表示一个core可以实现的超线程数
Core(s) per socket 表示一个socket上的core数
Socket(s) 表示socket的个数
NUMA node(s) 表示NUMA的结点数

这里如何计算呢?首先一块中央处理器(CPU),有多个插槽socket,每个socket中又有多个core,每个core又可以使用超线程技术模拟出多个线程(这个是逻辑CPU)。所以CPU(s)=SOckets * Cores * Threads

numactl

numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7
node 0 size: 15516 MB
node 0 free: 11705 MB
node 1 cpus: 8 9 10 11 12 13 14 15
node 1 size: 16100 MB
node 1 free: 1386 MB
node distances:
node   0   1 
  0:  10  21 
  1:  21  10

CPU分为两个node,也就是有两个CPU socket。
第一个node包含0-7号cpu,第二个node包含8-15个cpu
第一个node直连的内存是15516MB,第二个node直连的内存是161000MB
第一个node直连的内存空闲是11705MB,第二个node直连的内存是1386MB
node distances表示每个node访问对应的内存的距离,比如node0访问node0的距离是10,访问node1的距离是21。

numactl还有其他作用,比如绑定程序在哪一个node上执行,指定在哪个node上分配内存等。

numastat

numastat
                           node0           node1
numa_hit                18743091         9973793
numa_miss                      0               0
numa_foreign                   0               0
interleave_hit            101249          101451
local_node              18656240         9048143
other_node                 86851          925650

numa_hit 在node关联的内存上申请的内存数量
numa_miss 不在node关联的内存上申请的内存数量
numa_foreign 在其他node关联的内存上申请的内存数量
interleave_hit 采用interleave策略申请的内存数量
local_node 该node上的进程在该node关联的内存上申请的内存数量
other_node 该node上的进程在其他node关联的内存上申请的内存数量

关闭开启NUMA

在上面配置大页内存的一行加上numa=off,会关闭numa,理论上删除该字段,默认是开启。

调优经验

linux分配内存的策略是优先在自己node上分配内存,如果不够再考虑其他node上的内存,这是合理的。不过如果程序绑定的node内存不够,可以考虑绑定到其他node或者给程序运行的node多分配一些内存。

查看Node上的大页内存

上面我们介绍了,现代CPU都是有很多Node的,在NUMA架构下,配置在grub.cfg中的大页内存是被多个Node平分的。
比如我机器上按照上面配置了4个1G的大页内存,查看每个Node上的信息,Node0和Node1上各两个。

$ cat /sys/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages
2

$ cat /sys/devices/system/node/node1/hugepages/hugepages-1048576kB/nr_hugepages
2

大页内存配置目录介绍

/sys/devices/system/node目录下,可以看到系统中每一个Node对应的目录。在每个Node目录下/sys/devices/system/node/node0/hugepages,有关于大页内存的配置信息,一般有两个目录hugepages-1048576kB hugepages-2048kB,这是Linux系统支持的两种大页,一个是1G,一个是2M。

在每个大页内存目录下有三个文件free_hugepages nr_hugepages surplus_hugepages,分别表示当前Node,当前大页内存中空闲的大页内存数、设定的大页内存数,超出使用的大页内存数。

方法二 临时设置大页内存

如果想临时修改某个Node的大页内存,可以直接向对应的nr_hugepages写入对应数字,比如 echo 2 > /sys/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages

如果不想每个Node自己控制,可以向系统统一的大页内存文件写入数字 echo 2 > /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages,这个目录与上面的目录不一样,保存的是整个系统的大页内存配置。

注意 按照官方建议1GB的大页内存必须在grub设置,开机直接启用,不可在后续配置。
1. Getting Started — Soft Patch Panel 18.08.1 documentation

默认大页内存大小

7.3. 配置 HugeTLB Huge 页面 Red Hat Enterprise Linux 7 | Red Hat Customer Portal

上面说1GB的大页内存必须在grub中设置,开机分配,主要原因是怕后续分配没有这么大的连续空间,还有一个原因是系统默认分配的大页内存是2MB,开机之后,无法修改次默认配置(反正我试了很多方法),如果后续再分配1GB,dpdk会默认查找2MB的大页内存,发现没有会报错。

没有做任何大页内存配置时,查看cpu信息

cat /proc/meminfo|grep -i huge
AnonHugePages:     12288 kB
ShmemHugePages:        0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB

可以看到除了大页内存大小是2MB,其他的都是0。这就说明系统默认配置了2MB的大页内存,但是没有配置数量。

通过mount也可以看到挂载的大页内存信息

mount|grep -i hugepages
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime,pagesize=2M)

如果我们umount默认的大页内存,再通过动态分配1GB大页,再mount,都无法修改Hugepagesize,所以必须要在grub中配置,在开机时分配大页内存。

这里又有另外一个问题,开机分配大页内存,会被平均分配到每个numa node结点上。有时候网卡只在其中一个numa结点上,都分配,很明显浪费了空间,那么我们可以在配置grub的时候,把hugepages配置为0,其他配置为1GB,这样就可以默认挂载1GB大页内存,又不会额外分配空间,在系统启动后自动运行脚本按照需求在指定的numa结点上分配大页内存。

https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
Understanding Linux Kernel

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1518023.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CesiumJS-5】绘制动态路线实现飞行航线、汽车轨迹、路径漫游等

实现效果 前言 Cesium中&#xff0c;动态路线绘制的核心是借助CZML格式&#xff0c;CZML是一种用来描述动态场景的JSON数组,可以用来描述点、线、多边形、体、模型及其他图元,同时定义它们是怎样随时间变化的&#xff1b; CZML主要做三件事&#xff1a; 1.添加模型信息 2.添加…

Hadoop大数据应用:Yarn 节点实现扩容与缩容

目录 一、实验 1.环境 2.Yarn 节点扩容 3.Yarn 节点缩容 二、问题 1.yarn启动服务报错 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构软件版本IP备注hadoop NameNode &#xff08;已部署&#xff09; SecondaryNameNode &#xff08;已部署&…

【vue baidu-map】marker鼠标悬浮点击事件失效

要实现的效果&#xff1a;鼠标悬浮或者点击标注点会出现弹窗 验证过鼠标点击悬浮代码没问题&#xff0c;最后发现是控件样式影响的 ::v-deep #bjmap .BMap_noprint {inset: 10px 90% auto auto !important; } 只要增加上述样式&#xff0c;鼠标悬浮事件就会失效

QT使用dumpcpp为COM生成h及cpp的方式,COM是C#的dll注册的

目录 1.C#的dll注册为COM&#xff0c;采用bat的方式 2.通过qt的dumpcpp来生成h及cpp文件 3.h文件和cpp文件处理。 台达数控系统的C#的dll dumpcpp用的tlb文件 dumpcpp生成的原生h文件 dumpcpp生成的原生cpp dump生成后的的原生cpp文件修改后的cpp文资源 dump生成后的的…

【探索Linux】—— 强大的命令行工具 P.27(网络编程套接字 —— UDP协议介绍 | TCP协议介绍 | UDP 和 TCP 的异同)

阅读导航 引言一、UDP协议1. UDP简介2. UDP的特点3. UDP的使用场景4. UDP的局限性 二、TCP协议1. TCP简介2. TCP的特点3. TCP的应用场景 三、UDP 和 TCP 的异同温馨提示 引言 在上一篇文章中&#xff0c;我们深入探讨了Linux网络编程的基石——套接字&#xff08;Socket&#…

pytorch loss及其梯度

目录 1.loss的种类1.1 MSE1.2 MSE推导1.3 autograd.grad1.4 loss.backward 2. Softmax2.1 softmax推导 1.loss的种类 常见两种一种是均方差&#xff0c;一种是交叉熵 1.1 MSE 1.2 MSE推导 1.3 autograd.grad 1.4 loss.backward 注意&#xff1a;autograd.grad直接返回梯度&a…

守护健康,从营养开始 —— 帕金森患者的饮食秘籍

亲爱的读者朋友们&#xff0c;您是否知道&#xff0c;在对抗帕金森病的道路上&#xff0c;正确的饮食和营养补充可以成为我们的有力盟友&#xff1f;今天&#xff0c;就让我们一起探索那些能够帮助帕金森患者改善症状、提高生活质量的营养素&#xff0c;开启健康生活的新篇章。…

【保姆级】GPT的Oops问题快速解决方案

GPT的"Oops"问题通常指的是GPT在处理请求时突然遇到错误或无法提供预期输出的情况。要快速解决这个问题&#xff0c;可以尝试以下分步策略&#xff1a; 确认问题范围&#xff1a; 首先&#xff0c;确认问题是偶发的还是持续存在的。如果是偶发的&#xff0c;可能是临…

深度学习_GoogLeNet_4

目标 知道GoogLeNet网络结构的特点能够利用GoogLeNet完成图像分类 一、开发背景 GoogLeNet在2014年由Google团队提出&#xff0c; 斩获当年ImageNet(ILSVRC14)竞赛中Classification Task (分类任务) 第一名&#xff0c;VGG获得了第二名&#xff0c;为了向“LeNet”致敬&#x…

不同抓手的码垛机:适配多元应用场景的灵活之选

在现代工业生产中&#xff0c;码垛机作为一种高效、自动化的物料搬运设备&#xff0c;已经广泛应用于各个行业。而抓手作为码垛机的关键部件&#xff0c;其种类的多样性和适用场景的广泛性&#xff0c;使得不同抓手的码垛机能够满足各种复杂、多变的生产需求。 首先&#xff0c…

蓝桥杯单片机快速开发笔记——LED、蜂鸣器和继电器

一、原理分析 二、简单示例 总结&#xff1a;HC138令Y5C等于1后&#xff0c;通过控制P0^4、P0^6置1打开、置0关闭&#xff0c;便可以控制继电器和蜂鸣器,具体看上述的原理分析&#xff0c;LED同理通过给P0置0便可以控制LED点亮&#xff0c;利用本专栏上一节知识即可简单控制 …

vue 引用百度地图

address.vue <template><div><!-- 地图 --><el-drawer:visible.sync"type1"direction"rtl"size"50%"append-to-bodyclass"map-drawer":before-close"beforeClose"><div style"width: 100%…

Linux学习笔记(一)Linux基本指令

文章目录 前言目录常见命令1. pwd 打印当前所在路径2. cd 改变路径、切换路径3. 家目录 回到顶级目录4. 当前路径和上一路径5. 上一次路径6. 绝对路径和相对路径7. ls 列出目录内容8. mkdir 创建目录9. rmdir 删除目录10. touch 创建文件11. mv 修改文件目录、移动路径12. cp 复…

Vue3基础笔记(1)模版语法 属性绑定 渲染

Vue全称Vue.js是一种渐进式的JavaScript框架&#xff0c;采用自底向上增量开发的设计&#xff0c;核心库只关注视图层。性能丰富&#xff0c;完全有能力驱动采用单文件组件和Vue生态系统支持的库开发的复杂单页应用&#xff0c;适用于场景丰富的web前端框架。灵活性和可逐步集成…

一周学会Django5 Python Web开发-Jinja3模版引擎-模板语法

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计37条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

Linux系统架构----Tomcat 部署

一.Tomcat概述 Tomcat服务器是一个免费的开放式源代码的web应用服务器&#xff0c;属于轻量级应用级服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;是开发和调试JSP程序的首首选。 一般来说&#xff0c;tomcat虽然和Apache或者Nginx这些…

ThingsBoard 开源物联网平台

文章目录 1.ThingsBoard 介绍2.ThingsBoard 架构2.1.单体架构2.2.微服务架构 3.物联网网关4.边缘计算 ThingsBoard # ThingsBoardhttps://iothub.org.cn/docs/iot/ https://iothub.org.cn/docs/iot/thingsboard-ce/1.ThingsBoard 介绍 ThingsBoard 是一个开源物联网平台&…

MySQL 数据库 下载地址 国内阿里云站点

mysql安装包下载_开源镜像站-阿里云 以 MySQL 5.7 为例 mysql-MySQL-5.7安装包下载_开源镜像站-阿里云

C++ 拷贝构造函数和运算符重载

目录 一. 拷贝构造函数 1. 引入 2. 拷贝构造的概念 3. 浅拷贝 4. 深拷贝 二. C运算符重载 1. 概念 2. 注意事项 3.举例 一. 拷贝构造函数 1. 引入 我们在创建对象时&#xff0c;能不能创建一个与原先对象一模一样的新对象呢&#xff1f;为了解决这个问题&#x…

Qt/QML编程之路:基于QWidget编程及各种2D/3D/PIC绘制的示例(45)

关于使用GWidget,这里有一个示例,看了之后很多图形绘制,控件使用,及最基本的QWidget编程都比较清楚了。ui的绘制: 运行后的界面如 工程中有非常丰富的关于各种图形的绘制,比如上图中circle,还有image。有下面一段readme的说明: # EasyQPainter Various operation pra…