【八股】【C++】内存
这里写目录标题
- 内存空间分配
- new和delete原理
- C++有几种new
- malloc / free 与 new / delete区别
- malloc和free原理?
- delete和delete[]区别?
- C++内存泄漏
- malloc申请的存储空间能用delete释放吗?
- malloc、calloc函数、realloc函数
- C++中浅拷贝与深拷贝
- 栈和队列的区别
- C++里堆和栈的区别
- 堆快还是栈快
- 为什么C++没有垃圾回收机制?这点跟Java不太一样。
- 结构体内存的对齐?
- 获得结构成员相对于结构开头的字节偏移量
- 一个类对象占用的空间
- 实现内存池
- 堆和自由存储区
内存空间分配
首先,在C++里面大体可以把内存分为五个区,分别是:堆区、栈区、全局存储区、常量存储区和程序代码区。
- 堆:堆是我们通过new关键字来动态申请的内存空间,堆上分配的内存需要我们手动管理,如果我们没有正确释放堆上的内存可能会出现内存泄漏。
- 栈:存放局部变量和函数参数的地方,它在需要的时候会由编译器自动分配。当函数调用结束时栈上对应的空间会被自动释放。栈里执行的效率很高,但是分配的内存容量有限。
- 全局存储区:通常用来存储全局变量和静态变量。在C语言里面,全局变量又分为初始化的和未初始化的,但是C++里面没有这个区分。
- 常量存储区:这里通常用于存储常量数据,这部分内存是只读的。
- 程序代码区:它的主要功能就是存放程序的二进制代码,这部分内存一般也是只读的。通常代码区是可以共享的,因为对于频繁被执行的程序,只需要在内存中有一份代码就行了。
new和delete原理
new / delete是C++里的关键字,它们底层是执行的是C语言中的malloc和free,new / delete用于内存的动态申请和释放。
new的过程
先调用标准库里的operator new函数在堆上分配一块连续的内存空间;调用相应类的构造函数,对内存空间中的对象进行构造和初始化;最后返回指向这片空间的指针。
delete的过程
先调用对象的析构函数,完成对象资源的清理工作;然后调用标准库里的operator delete函数来释放这个对象所占用的空间。
C++有几种new
new是C++里面用来动态申请内存空间的关键字,它返回的是指定类型的指针。
广义上来说有三种常用的new,分别是new operator、operator new、placement new。
new operator也就是我们平时用的new操作符,我们用了之后它会有两个操作:
1.调用operator new 申请内存,operator new 是一个全局的函数。当使用 new 关键字的时候,编译器会自动找到这个函数,并且调用这个函数来分配空间。
2.调用类的构造函数进行初始化动作。
placement new:placement new又称为定位new运算符,它能够让我们指定需要使用的位置,定位new运算符直接使用传递给它的地址。
malloc / free 与 new / delete区别
- 它们都用于内存的动态申请和释放。malloc/free是C和C++语言里的标准库函数。new / delete是C++里的关键字,它底层是执行的malloc/free。。
- new/delete比malloc/free更加智能,因为malloc仅仅分配内存空间,free仅仅回收空间,它们并不具备调用构造函数和析构函数的功能。
new和delete在对象创建的时候能自动执行构造函数,对象消亡之前会自动执行析构函数,所以和malloc/free比起来更智能一些。 - new返回的直接就是我们指定类型的指针,而malloc返回void类型指针,我们必须要强行转换成实际需要的类型指针。
既然new/delete的功能完全覆盖了malloc和free,为什么C++中不把malloc/free淘汰出局呢?
因为c++程序经常要调用c函数,而c程序里只用malloc/free管理动态内存。
malloc和free原理?
- malloc:操作系统会维护一个记录空闲内存地址的链表,当调用malloc函数时,它就会去链表里找一个能够满足用户申请大小的内存块。然后把这个内存块分给用户,如果有多余的内存就继续返回到链表上。
- 当调用free函数时,它会把用户释放的内存块连接到空闲链表上。时间一长,空闲链表会被切成很多的小内存片段。再有用户申请一个大内存片段的话,那空闲链上可能没有可以满足用户要求大小的片段了。所以,malloc函数会请求延时,并开始在空闲链上整理内存片段,把相邻的小空闲块合并成大的内存块。如果实在不能找到符合要求的内存块,malloc函数会返回NULL指针。
delete和delete[]区别?
delete只会调用一次析构函数。delete[]会调用数组中每个元素的析构函数。
当new[]时,需要用delete[]来释放。new[]会创建一个对象数组,假设一个对象需要N字节大小,K个对象的数组就需要KN个空间。new[]会在KN个空间的基础上在头部多申请4个字节用于存储数组长度,delete[]时候会释放KN+4大小的内存。
C++内存泄漏
一般我们常说的内存泄漏指的是,我们在堆内存里动态申请的内存在使用完毕后没有释放掉,进而造成内存的浪费。总结一句话:就是new出来的内存没有通过delete合理的释放掉!
内存泄漏的情况:
1.new申请的内存没有释放
2.释放数组内存时用的是delete
3.父类的析构函数不是虚函数
可以使用智能指针解决
可以用计数法来解决,使用new或者malloc时,让该数+1,delete或free时,该数-1,程序执行完打印这个计数,如果不为0则表示存在内存泄露。
malloc申请的存储空间能用delete释放吗?
malloc和delete是不兼容的,malloc申请的空间应该使用free函数来释放。
malloc、calloc函数、realloc函数
malloc
void* malloc (size_t size);
// malloc函数用来动态开辟内存,返回void类型指针,我们必须要强行转换成实际需要的类型指针。
// 不会自动初始化,值为随机值
calloc函数
void* calloc (size_t num, size_t size);
// 为num个size大小的元素开辟一块空间,并且把空间的每个字节初始化为0。
realloc函数
realloc函数用来动态调整内存空间
void* realloc(void* ptr, size_t szie);
// ptr是需要调整的空间地址,size是调整之后新大小,返回参数为调整之后的内存起始位置。
存在两种情况:
1.原地扩容
在需要扩容的空间后有足够的空间进行扩容,要扩展内存就直接原有内存之后直接追加空间。
2.异地扩容
原有空间之后没有足够多的空间时,会在堆空间上另找一个合适大小的连续空间,并且把原内存空间的数据拷贝回来,释放旧的内存空间还给操作系统,最后返回一个新的内存地址。
C++中浅拷贝与深拷贝
浅拷贝
浅拷贝只是拷贝一个指针,并没有新开辟一个地址,新旧指针还是指向同一块内存地址。所以如果这个时候任意一个指针修改这块内存地址上的值,另一个指针指向的值也会跟着被修改。
深拷贝
深拷贝与浅拷贝的区别在于深拷贝不仅拷贝值,还会开辟出一块新的内存空间用来存放新的值,即使原先的对象被析构掉,也不会影响到深拷贝得到的值。
栈和队列的区别
栈
栈实际上是一种线性表,它只允许在固定的一端进行插入和删除元素。允许插入和删除的一端叫做栈顶,而不进行操作的一端叫做栈底。栈所遵循的原则是先进后出,主要的操作有push、top还有pop。其实我对它的理解它就是一个线性表,只不过这个线性表比较特殊,有个底儿,只能在另外一端进行插入和删除,就像个瓶子一样,最早放进去的东西,能拿出来是最晚的。
队列
队列和栈不一样,栈只能在一头进行插入和删除,而队列是两头都能用,具体是一头儿用来加新元素,另外一头用来删除元素。它所遵循的原则是先进先出,我对它的理解就是像火车进隧道,火车头就是队列头,火车尾就是队列尾。火车既然进隧道了,那肯定火车头先进那也先出,火车尾后进那肯定也就后出。
C++里堆和栈的区别
- 申请方式不同:堆是由我们自己用new和delete来申请和释放的,而频繁的new/delete会造成一定的内存碎片,所以分配的速度慢且会有碎片产生。而栈是由系统自动分配的,所以分配的速度快且不会有碎片。
- 内存连续不同:堆是不连续的内存区域,因为系统里是用链表来实现链接空闲地址的。而栈是一块儿连续的内存区域,大小也是操作系统预定好的。
- 管理机制不同:对于堆来说,系统有一个记录空闲内存地址的链表,当系统收到程序申请时就遍历这个链表,如果能够找到一个空间大于申请空间的堆节点,就会把这个节点空间分配给程序,然后删除链表里本节点记录。对于栈来说,只要栈的空余空间大于申请空间,系统就能分配成功,否则就要报栈溢出。
我自己的理解:栈就像是吃饭时候去饭店里吃,我们只管点菜付钱,方便便捷,但是饭的质量就不知道了,也就是没那么自由。而堆就是你亲自下厨,麻烦一点,但是自由度高,自己能够控制。
堆快还是栈快
栈快
这个问题可以从两方面来考虑:
- 内存分配释放角度,栈是程序运行前就已经分配好的空间,所以运行时几乎不需要再花费额外的时间去分配。但是堆的话是运行时动态申请的。
- 访问内存时间的角度,要访问堆的一个具体单元,需要两次访问内存,第一次得取得指针,第二次根据指针保存的地址来访问实际数据的内存。而栈只需访问一次。
既然栈更快,为什么不多用栈?
原因其实是栈的地址空间必须连续,如果让它任意成长的话,会给内存的管理带来困难。
为什么C++没有垃圾回收机制?这点跟Java不太一样。
1.首先,如果要实现一个垃圾回收器就会带来额外的空间和时间开销垃圾,这违反了C++的设计原则,也就是"不为不必要的功能付出代价",这不符合C++高效的特性。
2.C++有析构函数、智能指针、引用计数去管理资源的释放,对GC的需求并没有那么迫切.
3.消耗内存:C++产生的年代内存很少,垃圾回收机制需要占用更多的内存.
结构体内存的对齐?
要讲结构体内存对齐首先需要讲一下内存对齐是什么
我们都知道在内存中放数据之后CPU会来读取,但是CPU从内存中读取数据的时候并不是一个字节一个字节来读,而是以块儿的形式来读的,这个块儿的大小是内存的读取粒度。那么现在有几种情况:
第一种情况就是假如现在CPU从内存的0位置开始每次读8个字节,而我们的int数据刚好在内存的7~10位置处,这种情况CPU读这个int数据就要读两次(先0-7,再8-15),那这读一个int都要两次这效率太低了。
第二种情况:比如说现在有个结构体里面分别有一个char、一个int、一个char,那正常我们觉得这个结构体所占的内存就是1+4+1=6个字节,但我们实际sizeof的时候会显示它是占12个字节。那这就很奇怪对吧。
第三种情况:还是刚才这个结构体,里面三个元素按顺序是char、int、char,我们用sizeof的时候是12。但如果说,我们把它里面的元素顺序换一下,从char、int、char换成char、char、int,再用sizeof的时候就发现它占用的内存大小变成了8。那这几种情况其实都是内存是否对齐所带来的影响。
对于结构体来说,内存对齐是针对基本类型的。我们都知道结构体它里面的元素都是按照顺序定义的,依次放到内存里。实际上每个元素在放的时候都是有一个偏移量的,第一个元素的偏移量是0,其他元素的偏移量是对齐数的整数倍(那么所谓这个对齐数,指的是当前元素大小和当前编译器默认对齐数,它们两个之间的最小值),偏移了之后就开始放元素,当元素都放完之后,还需要看一下当前总的存储单元是不是这些元素中最大对齐数的整数倍,如果不是的话需要补成整数倍,也就是后面会空几个位置。
举个例子比如现在有个结构体,里面按顺序是一个char、一个int、一个double。那最开始的时候这个char变量存入第0个字节处,再放入int时,因为这个int的对齐数是它自己大小和当前编译器默认对齐数的最小值(也就是4和8比较),所以这个int的对齐数是4.由于内存里第一个四个字节的位置已经有了数据,所以它会存到第二个四字节里,也就是第4~7处。再放入double,同理第一个8字节的位置已经被占了,所以它存到第8-15位置上。元素都放完之后,再来看看已经占用的内存字节数是不是元素里最大对齐数的整数倍,是就结束,不是就在后面补上空的位置。
在C++11以后引入了两个关键字 alignas 和 alignof。alignas可以指定结构体的对齐量,alignof可以计算出类型的对齐量。如果alignas指定的值小于自然对齐的最小单位,那它就会失效。
总体来说:
结构体的内存对齐就是拿空间换时间。用了内存对齐之后,CPU访问内存的效率会更高,而且有一些硬件平台可能必须要求内存对齐,否则抛出异常。那所以这就是我对结构体的内存对齐的一些理解。
获得结构成员相对于结构开头的字节偏移量
使用<stddef.h>头文件中的,offsetof宏。
struct S
{int x;char y;int z;double a;
};
int main()
{cout << offsetof(S, x) << endl; // 0cout << offsetof(S, y) << endl; // 4cout << offsetof(S, z) << endl; // 8cout << offsetof(S, a) << endl; // 12return 0;
}
一个类对象占用的空间
- 非静态成员变量所占大小总和。
- 加上编译器为了CPU计算,作出的数据对齐处理。
- 加上为了支持虚函数,产生的额外内存。
因为当有虚成员函数的类实例化的时候,会有一个指针vptr指向虚函数表vtbl,而虚函数表里就存储着类中定义的所有虚函数。所以虚函数引起的额外内存占用就是指针vptr占用内存的大小。
空类(无非静态数据成员)的实例大小为1, 因为不同的对象不能具有相同的地址,所以编译器会给空类加上1个字节,保证用这个类定义的对象都有一个独一无二的地址。
类的静态成员变量不占用类的存储空间,因为类里的静态成员存储在全局数据区中,全局只有一份。
类的成员函数(除虚函数外)不占用类的存储空间,因为成员函数(包括构造和析构函数)编译后存放在程序代码区。
实现内存池
首先讲一下为什么需要内存池:
通常我们习惯直接使用new、malloc等API申请内存,这样做的缺点在于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。而内存池则是在真正使用内存之前,预先申请分配一定数量的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是,使得内存分配效率得到提升。
经典内存池设计:
(1)先申请一块连续的内存空间,把这块内存空间划分为若干个子内存块,每个子内存块连同一个指向下一个内存块的指针一起构成一个内存节点,然后用指针把这些内存节点连接成一个链表,链表的每一个内存节点都是一块可供分配的内存空间;;
(2)如果有内存节点分配出去,就从空闲节点链表中删除这个节点;如果有内存节点被释放,就把这个节点重新加入空闲内存节点链表里;
(3)当一个内存块的所有内存节点都已经分配出去了,还要申请新的对象空间,就会再去申请一个内存块来容纳新的对象,再新申请的内存块加入到内存块链表中。
堆和自由存储区
自由存储区:自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行的内存申请,这块内存就在自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存。
简而言之:堆是操作系统维护的一块内存,而自由存储是C++中通过new与delete动态分配和释放对象的抽象概念,堆与自由存储区并不等价。
相关文章:

【八股】【C++】内存
这里写目录标题 内存空间分配new和delete原理C有几种newmalloc / free 与 new / delete区别malloc和free原理?delete和delete[]区别?C内存泄漏malloc申请的存储空间能用delete释放吗?malloc、calloc函数、realloc函数C中浅拷贝与深拷贝栈和队列的区别C里…...

数据库G等待
> db^Cgbasedbtpc:~$ dbaccess db10 -Database selected.> call insert_t();Routine executed.Elapsed time: 811.630 sec 磁盘逻辑日志,无BUF库> ^Cgbasedbtpc:~$ gbasedbtpc:~$ dbaccess db10 -Database selected.> call insert_t();Routine executed.Elapse…...

PCB封装设计指导(一)基础知识
PCB封装设计指导(一)基础知识 PCB封装是PCB设计的基础,也是PCB最关键的部件之一,尺寸需要非常准确且精确,关系到设计,生产加工,贴片等后续一系列的流程。 下面以Allegro为例介绍封装创建前的一些基础知识 1.各个psm文件代表什么 mechanical symbol 是.bsm Package sy…...

Flask框架之Restful--介绍--下载--基本使用
目录 Restful 概念 架构的主要原则 适用场景 协议 数据传输格式 url链接规则 HTTP请求方式 状态码 Restful的基本使用 介绍 优势 缺点 安装 基本使用 注意 Restful 概念 RESTful(Representational State Transfer)是一种用于设计网络应用…...

2023年上海市浦东新区网络安全管理员决赛理论题样题
目录 一、判断题 二、单选题 三、多选题 一、判断题 1.等保1.0至等保2.0从信息系统拓展为网络和信息系统。 正确 (1)保护对象改变 等保1.0保护的对象是信息系统,等保2.0增加为网络和信息系统,增加了云计算、大数据、工业控制系统、物联网、移动物联技术、网络基础…...

SQL语言的四大组成部分——DCL(数据控制语言)
1️⃣前言 SQL语言中的DCL(Data Control Language)是一组用于控制数据库用户访问权限的语言,主要包括GRANT、REVOKE、DENY等关键字。 文章目录 1️⃣前言2️⃣DCL语言3️⃣GRANT关键字4️⃣REVOKE关键字5️⃣DENY关键字6️⃣总结附࿱…...

ChatGPT新功能曝光:可记住用户信息、上传文件和工作区
🦉 AI新闻 🚀 ChatGPT新功能曝光:可记住用户信息、上传文件和工作区 摘要:一张神秘截图曝光了ChatGPT新功能,包括可记住用户信息的"My profile"、上传和管理文件的"My files"以及可以让AI使用不…...

【Unity编辑器扩展】(三)PSD转UGUI Prefab, 一键拼UI解放美术/程序(完结)
工具效果: 第一步,把psd图层转换为可编辑的节点树,并自动解析UI类型、自动绑定UI子元素: 第二步, 点击“生成UIForm"按钮生成UI预制体 (若有UI类型遗漏可在下拉菜单手动点选UI类型): 验证一键生成UI效果: 书接上…...

SpringBoot开发Restful风格的接口实现CRUD功能
基于SpringBoot开发一个Restful接口 前言一、什么是SpringBoot?二、实战---基于SpringBoot开发一个Restful接口1.开发前的准备工作1.1 添加相关依赖 (pom文件) 1.2 创建相关数据库和表1.3 数据库配置文件 2.实战开发---代码逻辑2.1 实体类2.2…...

【Servlet学习三】实现一个内存版本的简易计算器~
目录 一、方式1:使用form表单的形式(不推荐) 🌈1、前端代码:HTML文件 🌈2、后端代码:Calculator_form.java文件 🌈3、最终效果 二、方式2:使用ajax形式(…...

Linux c语言获取本机网关 ip 地址
文章目录 前言一、获取本机网关 ip 地址1.1 代码示例1.2 代码详解介绍 二、使用Netlink套接字实时监控网络事件2.1 简介2.2 示例代码 前言 这篇文章写了获取本机的ip地址和子网掩码:Linux c语言获取本机 ip、子网掩码 一、获取本机网关 ip 地址 使用Netlink套接字…...

nginx部署本地项目如何让异地公网访问?服务器端口映射配置!
接触过IIS或apache的小伙伴们,对nginx是比较容易理解的,nginx有点类似,又有所差异,在选择使用时根据自己本地应用场景来部署使用即可。通过一些对比可能会更加清楚了解: 1.nginx是轻量级,比apache占用更少…...

云时代已至,新一代数据分析平台是如何实现的?
2023 年 5 月,由 Stackoverflow 发起的 2023 年度开发者调查数据显示,PostgreSQL 已经超越 MySQL 位居第一,成为开发人员首选。PostgreSQL 在国内的热度也越来越高。6 月 17 日,PostgreSQL 数据库技术峰会在成都顺利召开。本次大会…...

【C#】简单聊下Framework框架下的事务
框架用的多了,之前版本的事务都忘记了。本次简单聊下.net framework 4.8框架下本身的事务 目录 1、SqlClient2、TransactionScope3、引用 1、SqlClient 在 C# 中,使用 using 块可以方便地实现对资源的自动释放,但它不适用于实现事务处理。为…...

asyncPool并发执行请求函数
asyncPool应用场景 一个不太常见的极端场景,当我们为了某个操作需要发生异步请求的时候,等待所有异步请求都完成时进行某些操作。这个时候我们不在简简单单的发送 1 - 2 个请求而是 5 - 10个(其实极端场景式 很多很多个请求,这个…...

Ubuntu 22.04上安装NFS服务
1、使用如下命令安装NFS服务端软件: # 在主机上运行以下命令 orangepiorangepi5:~$ sudo apt install nfs-server 2、在配置NFS时需要使用用户uid和组gid,可以使用id命令查看 # 在主机上运行id命令 orangepiorangepi5:~$ id uid1000(orangepi) gid100…...

数据结构--双链表
数据结构–双链表 单链表 VS 双链表 单链表:无法逆向检索,有时候不太方便 双链表:可进可退,存储密度更低一丢丢 双链表的定义 typedef struct DNode {ElemType data;struct DNode *prior, *next; }DNode, *DLinkList;双链表的初…...

javassist 动态修改 jar 包中 class
Javassist(Java Programming Assistant)是一个用于在运行时操作字节码的库,它可以用于动态修改和操作Java类。使用Javassist,可以通过修改现有的类或创建新的类来实现动态修改Jar包中的类。 下面是一个简单的示例,展示…...

什么是CC攻击?
CC攻击:DDOS(分布式拒绝服务攻击)的一种。黑客利用代理服务器或者控制的肉鸡,向目标web网页发送大量的请求,致使CPU处理不过来这么多的请求,长期处于100%的状态。造成通过该页面访问的端口堵塞,正常请求进不来。 怎么…...

LeetCode解法汇总253. 重构 2 行二进制矩阵
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 给你一个 2 行 n 列的二进制数组: 矩阵是一个二进制矩阵࿰…...

ChatGPT实战:生成演讲稿
当众发言(演讲)是一种传达信息、观点和情感的重要方式。通过演讲,人们可以在公共场合表达自己的观点,向观众传递自己的知识和经验,激发听众的思考和行动。无论是商务演讲、学术讲座还是政治演说,演讲稿的写…...

在线搭建K8S,kubernetes集群v1.23.9,docker支持的最后一个版本
1. 部署环境主机(条件说明) master 192.168.186.128 CentOS Linux release 7.9.2009 (Core) node1 192.168.186.129 CentOS Linux release 7.9.2009 (Core) node2 192.168.186.130 CentOS Linux release 7.9.2009 (Core)2. 系统初始化-所有节点&am…...

http自动跳转https的配置方法
要将HTTP自动重定向到HTTPS,您需要在Web服务器上进行以下配置: 在Web服务器上安装SSL证书。 打开Web服务器配置文件(如Apache的httpd.conf或Nginx的nginx.conf)。 找到监听HTTP请求的端口(通常是80端口)。…...

重新初始化k8s集群
执行如下命令,所有节点都执行 kubeadm reset初始化集群,仅在master(centos01)上执行 [rootcentos01 opt]# kubeadm init --apiserver-advertise-address 192.168.109.130 --image-repository registry.aliyuncs.com/google_containers --kubernetes-ve…...

JetBrains编程IDE将具备Ai助手功能,或将提高开发速度
近日JetBrains发布博客文章宣布,本周所有基于IntelliJ的IDE和.NET工具的EAP版本都将具备AI助手功能。而这些操作或许将提高开发效率,并且这些AI助手也是使用自家的**ERP**模型和OpenAI服务。 JetBrains表示,当下AI助手功能主要体现在IDE的两…...

【网络原理】TCP/IP协议五层模型
🥊作者:一只爱打拳的程序猿,Java领域新星创作者,CSDN、阿里云社区优质创作者。 🤼专栏收录于:计算机网络原理 本期讲解协议、OSI七层模型、TCP/IP五层模型、网络设备所在的分层、数据的封装和分佣。 目录 …...

【备战秋招】每日一题:2023.05.10-华为OD机试(第二题)-解密
为了更好的阅读体检,可以查看我的算法学习博客 在线评测链接:P1307 题目内容 在全球恐怖主义危机下,一组间谍团队接收到了来自地下工作者的一串神秘代码。这组代码可以帮助他们访问恐怖分子的服务器,但是他们需要先解密代码才能使用它。代…...

【华为OD机试】矩阵最大值(python, java, c++, js)
矩阵最大值 前言:本专栏将持续更新华为OD机试题目,并进行详细的分析与解答,包含完整的代码实现,希望可以帮助到正在努力的你。关于OD机试流程、面经、面试指导等,如有任何疑问,欢迎联系我,wechat:steven_moda;email:nansun0903@163.com;备注:CSDN。 题目描述 给定…...

通过USB和wifi连接真机编写第一个脚本
目录 一、连接手机 1、通过usb数据线连接手机 2、无线连接手机 二、编写第一个脚本 一、连接手机 1、通过usb数据线连接手机 数据线连接手机并允许调试 cmd命令行执行: adb devices 如果没有显示device信息,请检查: 手机是否开启usb调…...

【javascript】 javascript对象函数 总结
Object.entries( ) 作用:返回一个数组,获取对象所有可枚举属性的名称 和 可枚举属性的值 const obj { a: 1, b: 2 }; const entries Object.entries(obj); console.log(entries); // [[a, 1], [b, 2]] Object.keys( ) 作用:返回一个数组…...